C# 使用Queue 代替遞歸算法遍歷樹


    遞歸時候每次調用自身在堆棧上要記錄返回地址,而堆棧的空間很少,調用次數多了后會產生堆棧溢出,以下代碼是實際項目中,通過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>,根據實際需要選擇,如有沒有順序要求。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM