C# 如何在不使用递归c的情况下遍历此树结构#

C# 如何在不使用递归c的情况下遍历此树结构#,c#,performance,tree,recursive-datastructures,C#,Performance,Tree,Recursive Datastructures,这段代码将循环数据保存在数据库中,但我遇到了性能问题,因为数据太大,它会保存大量记录,在这种情况下,递归会对内存造成非常大的负载,因此我需要一个递归的替代解决方案,因为这是一个n元树 private void ProcessLoops(LoopContainer parent, InboundLoop parentLoop) { foreach (var segment in parent.Segments) { if (s

这段代码将循环数据保存在数据库中,但我遇到了性能问题,因为数据太大,它会保存大量记录,在这种情况下,递归会对内存造成非常大的负载,因此我需要一个递归的替代解决方案,因为这是一个n元树

    private void ProcessLoops(LoopContainer parent, InboundLoop parentLoop)
    {
        foreach (var segment in parent.Segments)
        {
            if (segment is Loop)
            {
                var segmentLoop = segment as Loop;
                var inboundLoop = new InboundLoop()
                {
                    Inbound834RegisterId = RegisterId,
                    InboundSTId = InboundST.InboundSTId,
                    LoopName = segmentLoop.Specification.Name,
                    LoopNumber = segmentLoop.Specification.LoopId,
                    Sequence = _loopSequence++
                };

                if (parentLoop == null)
                {
                    inboundLoop.InboundLoopId = InboundLoopService.Instance.AddInboundLoop(inboundLoop);
                }
                else
                {
                    inboundLoop.ParentLoopId = parentLoop.InboundLoopId;
                    inboundLoop.InboundLoopId = InboundLoopService.Instance.AddInboundLoop(inboundLoop);
                }
                ProcessLoops(segmentLoop, inboundLoop);
            }
        }
    }

每个递归都可以设置为循环。
对于深度搜索,您可以:

  • 将根目录放入队列(先进先出)
  • 弹出队列时,您将该项的所有子项放入队列中
  • 将该项保存到数据库中
  • 编辑:为每个请求添加代码

    var nodeQueue = new Queue<Node>();
    nodeQueue.Add(Tree.Root);
    while (!nodeQueue.Empty())
    {
        var item = nodeQueue.Pop();
        foreach(Node child in item.Children)
        {
            nodeQueue.Add(child);
        }
        db.Add(item.Data);
    }   
    
    var length = Tree.Count;
    var depth = Tree.Depth;
    var maxLength = Power(2,depth)-1
    for (var i=0; i<maxLength; i++)
    {
        db.Add(Tree.GetByNumber(i));
    }
    
    var nodeQueue=new Queue();
    nodeQueue.Add(Tree.Root);
    而(!nodeQueue.Empty())
    {
    var item=nodeQueue.Pop();
    foreach(item.Children中的节点子节点)
    {
    nodeQueue.Add(子节点);
    }
    db.Add(项目数据);
    }   
    
    另一种方法,需要更多时间,即计算树中项目的最大数量(我假设它可能不平衡)

  • 在从0到MaxItems的循环中运行
  • 将每个数字转换为二进制
  • 左用0,右用1
  • 对于每个数字,请相应地移入 那棵树。 这样,每个数字代表树中的单个节点,您可以按特定顺序在树中循环
  • 编辑:为每个请求添加代码

    var nodeQueue = new Queue<Node>();
    nodeQueue.Add(Tree.Root);
    while (!nodeQueue.Empty())
    {
        var item = nodeQueue.Pop();
        foreach(Node child in item.Children)
        {
            nodeQueue.Add(child);
        }
        db.Add(item.Data);
    }   
    
    var length = Tree.Count;
    var depth = Tree.Depth;
    var maxLength = Power(2,depth)-1
    for (var i=0; i<maxLength; i++)
    {
        db.Add(Tree.GetByNumber(i));
    }
    
    var length=Tree.Count;
    var depth=Tree.depth;
    var maxLength=功率(2,深度)-1
    对于(var i=0;i
    公共类节点信息
    {
    公共对象节点{get;set;}
    公共队列属性被访问{get;set;}
    }
    公共静态类类型扩展
    {
    公共静态bool IsComplex(此类型)
    {
    return!type.IsValueType&&type!=typeof(字符串);
    }
    公共静态布尔IsCollection(此类型)
    {
    var collectionTypeName=typeof(ICollection).Name;
    返回类型.Name==collectionTypeName | | type.GetInterface(typeof(ICollection).Name)!=null;
    }
    }
    公共静态void遍历对象树(对象数据)
    {
    var currentNode=数据;
    var currentNodeProperties=新队列(data.GetType().GetProperties());
    var nodeTracker=新队列();
    while(currentNodeProperties.Count!=0 | | nodeTracker.Count!=0)
    {
    如果(currentNodeProperties.Count==0&&nodeTracker.Count!=0)
    {
    var currentNodeInfo=nodeTracker.Dequeue();
    currentNode=currentNodeInfo.Node;
    currentNodeProperties=currentNodeInfo.PropertiesToBeVisited;
    继续;
    }
    var currentNodeProperty=currentNodeProperties.Dequeue();
    var currentNodePropertyType=currentNodeProperty.PropertyType;
    if(currentNodePropertyType.IsComplex())
    {
    var value=currentNode?.GetType().GetProperty(currentNodeProperty.Name)
    ?.GetValue(currentNode,null);
    if(值!=null)
    {
    对象节点;
    if(currentNodePropertyType.IsCollection())
    {
    var elementType=currentNodePropertyType.IsArray
    ?value.GetType().GetElementType()
    :value.GetType().GetGenericArguments()[0];
    node=Activator.CreateInstance(elementType??抛出新的InvalidOperationException());
    }
    其他的
    {
    节点=值;
    }
    nodeTracker.Enqueue(新节点信息
    {
    节点=当前节点,
    PropertiesToBeVisited=currentNodeProperties
    });
    currentNode=节点;
    currentNodeProperties=新队列(node.GetType().GetProperties());
    Console.WriteLine(currentNodeProperty.Name);
    继续;
    }
    }
    Console.WriteLine(currentNodeProperty.Name);
    }
    }
    

    这将完成任务!!

    我创建了一种方法,可以将项目按递归处理的顺序展开,而不使用递归。由于这是一种通用的扩展方法,它可以用于任何事情。例如,您可以将
    T
    作为
    操作
    ,以便您可以随时处理它们xtension方法:

    公共静态类EnumerableExtensions
    {
    公共静态列表到递归OrderList(此IEnumerable集合、表达式childCollection)
    {
    var resultList=新列表();
    var currentItems=新队列(collection.Select(i=>(0,i,0));
    var-depthItemCounter=0;
    var previousItemDepth=0;
    var childProperty=(PropertyInfo)((MemberExpression)childCollection.Body.Member;
    而(currentItems.Count>0)
    {
    var currentItem=currentItems.Dequeue();
    //当深度改变时,重置此深度处项目数的计数器。
    如果(currentItem.Depth!=previousItemDepth)depthItemCounter=0;
    var resultIndex=currentItem.Index+depthItemCounter++;
    resultList.Insert(resultIndex,currentItem.Item);
    var childItems=childProperty.GetValue(currentItem.Item)作为IEnumerable??Enumerable.Empty();
    foreach(childItems中的var childItem)
    {
    currentItems.Enqueue((resultIndex+1,childItem,currentItem.Depth+1));
    }
    previousItemDepth=currentItem.Depth;
    }
    返回结果列表;
    }
    }
    
    下面是一个如何使用它的示例。像这样的结构将被展平

    • A
    • B
    • C
      • D
        • E
      • F
      • G
      • H
    • J
      • K
      • L
        • M
    • N
    • O
      • P