C# 仅使用parentId的层次结构数据的有效排序

C# 仅使用parentId的层次结构数据的有效排序,c#,hierarchical-data,C#,Hierarchical Data,问题 对一组无序的节点进行排序的最快方法是什么,这样父节点总是在其子节点之前列出。我当前的解决方案使用队列以广度优先的方式迭代树。然而,我一直在想是否有更好/更有效的方法 注: 我不能预先计算任何值 Id和ParentId也可以是guid(即使ints不能保证顺序Id) Linq Pad代码 void Main() { var nodes = new Node[] { new Node { Id = 7, ParentId = 3 }, new Nod

问题

对一组无序的节点进行排序的最快方法是什么,这样父节点总是在其子节点之前列出。我当前的解决方案使用队列以广度优先的方式迭代树。然而,我一直在想是否有更好/更有效的方法

注:

  • 我不能预先计算任何值
  • Id和ParentId也可以是guid(即使ints不能保证顺序Id)
Linq Pad代码

void Main()
{
    var nodes = new Node[] {
        new Node { Id = 7, ParentId = 3 },
        new Node { Id = 4, ParentId = 2 },
        new Node { Id = 1, ParentId = 0 },
        new Node { Id = 2, ParentId = 1 },
        new Node { Id = 3, ParentId = 1 },

        new Node { Id = 5, ParentId = 2 },
        new Node { Id = 6, ParentId = 3 },
        new Node { Id = 8, ParentId = 0 },
    };

    SortHierarchy(nodes).Dump();
}

IEnumerable<Node> SortHierarchy(IEnumerable<Node> list)
{
    // hashtable lookup that allows us to grab references to the parent containers, based on id
    var lookup = new Dictionary<int, List<Node>>();

    Queue<Node> nodeSet = new Queue<Node>();
    List<Node> children;

    foreach (Node item in list) {
        if (item.ParentId == 0) { // has no parent
            nodeSet.Enqueue(item); // This will add all root nodes in the forest
        } else {
            if (lookup.TryGetValue(item.ParentId, out children)) {
                // add to the parent's child list
                children.Add(item);
            } else {
                // no parent added yet
                lookup.Add(item.ParentId, new List<Node> { item });
            }
        }
    }

    while (nodeSet.Any()) {
        var node = nodeSet.Dequeue();
        if (lookup.TryGetValue(node.Id, out children)) {
            foreach (var child in children) {
                nodeSet.Enqueue(child);
            }
        }
        yield return node;
    }
}

private class Node {
    public int Id { get; set; }
    public int ParentId { get; set; }
    public string Name { get; set; }
}
void Main()
{
变量节点=新节点[]{
新节点{Id=7,ParentId=3},
新节点{Id=4,ParentId=2},
新节点{Id=1,ParentId=0},
新节点{Id=2,ParentId=1},
新节点{Id=3,ParentId=1},
新节点{Id=5,ParentId=2},
新节点{Id=6,ParentId=3},
新节点{Id=8,ParentId=0},
};
SortHierarchy(节点).Dump();
}
IEnumerable SortHierarchy(IEnumerable列表)
{
//哈希表查找,允许我们根据id获取对父容器的引用
var lookup=newdictionary();
队列节点集=新队列();
列出儿童名单;
foreach(列表中的节点项){
如果(item.ParentId==0){//没有父项
nodeSet.Enqueue(item);//这将添加林中的所有根节点
}否则{
if(lookup.TryGetValue(item.ParentId,out子项)){
//添加到父对象的子列表中
添加(项目);
}否则{
//还没有添加家长
添加(item.ParentId,新列表{item});
}
}
}
while(nodeSet.Any()){
var node=nodeSet.Dequeue();
if(lookup.TryGetValue(node.Id,out子节点)){
foreach(儿童中的儿童变量){
节点集排队(子节点);
}
}
收益回报节点;
}
}
私有类节点{
公共int Id{get;set;}
public int ParentId{get;set;}
公共字符串名称{get;set;}
}
研究

我确实发现了这一点,但这并不是我想要的(代码也不起作用)


此代码给出相同的dump()结果,请先使用parentid对列表排序:

IEnumerable<Node> SortHierarchy2(IEnumerable<Node> list)
{
    return list.OrderBy(l => l.ParentId);
}
IEnumerable SortHierarchy2(IEnumerable列表)
{
return list.OrderBy(l=>l.ParentId);
}

只要你的孩子Id是<他们的父母Id。

@HamletHakobyan代码运行良好。你能相信<代码>父母Id小于<代码>Id,或者这只是巧合吗?@Rawling不,我不能相信如果孩子Id总是>父母Id,您甚至可以按
Id
排序。仅按
ParentId
排序要比OP的方法慢得多。这就是为什么他要求一个适合他的特殊情况的算法。按
Id
排序更慢。按Id排序怎么会更慢?它是O(nlg(n))。运行几次后,速度大致相同。有时排序更快,有时是原始方法。