我正在研究C#,我正在寻找一种简单的方法来获取表示树的列表,并将树平放到与树中的顺序相同的列表。
每个节点有4个属性:
* ID
* ParentID,
* Seq
*姓名
public class MyNode
{
public int ID{get;set;}
public int ParentID{get;set;}
public int SeqID{get;set;}
public string Name{get;set;}
}
我有一个MyNode的集合:
List<MyNode> FlatListOfNodes{get;set;}
我正在寻找看起来像这样的东西:
FlatListOfNodes.OrderBy(something).DoAnotherThing1(somthing)...
。
将按照树中的顺序对列表进行排序。
例如,如果有这棵树:
-- Parent1
-- Child 1.1
-- Child 1.2
-- grandson 1.2.1
-- grandson 1.2.2
-- grandson 1.2.3
-- Child 1.3
-- Parent2
-- Child 2.1
-- Child 2.2
-- grandson 2.2.1
-- grandson 2.2.2
-- grandson 2.2.3
-- Child 2.3
-- grandson 2.3.1
-- grandson 2.3.2
我希望通过相同的顺序在平面列表中表示它。
在这个例子中:
最好的方法是什么?
有没有办法用linq做到这一点?
谢谢!
答案 0 :(得分:2)
您的树可以概括为m-ary tree。鉴于此,您可以通过执行该树的深度优先遍历(DFT)来计算您的平面列表。我怀疑这将是最快的,因为LINQ不假设您的数据结构有任何明确的结构。 Here's a quick article on DFT for binary search trees - m-ary树的DFT是该概念的抽象。
您的任何状态变量似乎都没有自然排序。您必须想出一些方法来打破孩子之间的联系(例如,为什么在Parent2之前访问Parent1-某个比较器告诉算法首先访问Parent1)。比较可以基于生成顺序这样简单的事情(例如,最老的孩子优先)。如下面的评论中所述,比较SeqID以选择要递归的下一个焦点节点。
答案 1 :(得分:0)
你可以两次通过。首先,您创建一个节点字典,每个节点都有一个子列表。
class TreeNode
{
public MyNode NodeData;
public List<MyNode> Children = new List<MyNode>();
}
例如:
Dictionary<int, MyNode> nodesDict = new Dictionary<int, MyNode>();
// add the parent node
nodesDict.Add(-1, new TreeNode{NodeData = new MyNode{ID=1, ParentID=0, SeqID=1, Name="Root"}});
// now go through the original list of nodes
foreach (var node in NodesList)
{
// If there is an entry for this node already in the dictionary,
// then update its NodeData.
// Otherwise create a new entry.
TreeNode dictNode;
if (nodesDict.TryGetValue(node.ID, out dictNode))
{
dictNode.NodeData = node;
}
else
{
// add this node to the dictionary
dictNode = new TreeNode{NodeData = node};
nodesDict.Add(node.ID, dictNode);
}
// find this node's parent, and add the node to the child list
// if the node's parent doesn't exist, add it
TreeNode parentNode;
if (!nodesDict.TryGetValue(node.ParentID, out parentNode))
{
// Parent doesn't yet exist.
// Create an entry for it.
parentNode = new TreeNode();
nodesDict.Add(node.ParentID, parentNode);
}
// Add this node to the parent's children
parentNode.Children.Add(node);
}
现在你拥有的是一个字典,其中包含每个树节点的条目,树节点知道他们的孩子是什么。此时,您关心的只是ID为-1的节点。所有其他节点都可以从那里到达。
var root = nodesDict[-1];
var children = root.Children.OrderBy(n -> n.SeqID);
OutputNodes(children);
OutputNodes
方法可以递归访问子节点来构建平面列表:
List<MyNode> FlatList = new List<MyNode>();
void OutputNodes(IEnumerable<TreeNode> nodes)
{
foreach (var node in nodes)
{
FlatList.Add(node);
// and then the children
var orderedChildren = node.Children.OrderBy(n -> n.SeqID);
OutputNodes(orderedChildren);
}
}
这是我知道怎么做的最好方式。我不知道你怎么能用LINQ做到这一点。