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)
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))。运行几次后,速度大致相同。有时排序更快,有时是原始方法。