遞歸時候每次調用自身在堆棧上要記錄返回地址,而堆棧的空間很少,調用次數多了後會產生堆棧溢出,以下代碼是實際項目中,通過Queue<T>來避免遞歸演算法的代碼: /// <summary> /// 獲取某個節點下特定屬性的所有子孫節點 /// </summary> /// <param name="gr ...
遞歸時候每次調用自身在堆棧上要記錄返回地址,而堆棧的空間很少,調用次數多了後會產生堆棧溢出,以下代碼是實際項目中,通過Queue<T>來避免遞歸演算法的代碼:
/// <summary>
/// 獲取某個節點下特定屬性的所有子孫節點
/// </summary>
/// <param name="groupId"></param>
/// <returns></returns>
public IList<OfficeGroupNodeDto> GetSelfAndChildOfficesByGroupId(int groupId)
{
Func<int, string, BusinessType, int, string, OfficeGroupNodeDto> createGroupNodeFunc =
(id, name, bizType, parentId, parentName) =>
new OfficeGroupNodeDto()
{
OfficeId = id,
Name = name,
BizType = bizType,
ParentId = parentId,
ParentName = parentName
};
var offices = GetTenantOffices().ToArray();
Func<int, OfficeDto[]> getChildOfficesFunc = id => offices.Where(x => x.ParentId == id).ToArray();
//創建隊列
var groupNodeCacheQueue = new Queue<OfficeGroupNodeDto>();
var currentGroup = groupId == 0 || groupId == Office.AdminOffice.Id
? ToDto(Office.AdminOffice)
: offices.FirstOrDefault(x => x.Id == groupId && x.OfficeType == OfficeType.Group);
if (currentGroup == null) return null;
var officeGroupNodeDto =
createGroupNodeFunc(currentGroup.Id, currentGroup.Abbreviation, currentGroup.BizType, 0, string.Empty);
//初始進入隊列一個元素
groupNodeCacheQueue.Enqueue(officeGroupNodeDto);
//迴圈讀取隊列內元素,直到讀取完
while (groupNodeCacheQueue.Count > 0)
{
//出隊列一個元素節點
var currentGroupNode = groupNodeCacheQueue.Dequeue();
//獲取該節點的所有孩子節點
var childOffices = getChildOfficesFunc(currentGroupNode.OfficeId);
currentGroupNode.IsGroup = true;
var hasChildren = childOffices.SafeAny();
currentGroupNode.HasChildren = hasChildren;
if (!hasChildren) continue;
//遍歷當前節點的孩子節點
foreach (var office in childOffices)
{
if (office.BizType == BusinessType.FranchiseChain) continue;
//創建符合條件的節點
var newNode = createGroupNodeFunc(office.Id, office.Abbreviation, BusinessType.RegularChain,
currentGroupNode.OfficeId, currentGroupNode.Name);
currentGroupNode.Items.Add(newNode);
if (office.OfficeType == OfficeType.Office) continue;
//把還有子節點的孩子元素節點到隊列,待下次迴圈繼續
groupNodeCacheQueue.Enqueue(newNode);
}
}
return new List<OfficeGroupNodeDto>() { officeGroupNodeDto };
}
註:主要看註釋部分的總體思路,其他次要細節不用太關註
當然這裡也可以用其他數據結構如Stack<T>,根據實際需要選擇,如有沒有順序要求。