我有一个对象集合(List<Element>
),如下所述:
class Element
{
string Name;
string Value;
ICollection<Element> ChildCollection;
IDictionary<string, string> Attributes;
}
我根据我读到的一些XML构建了List<Element>
个Element
个对象的集合,我很满意。如何实现这些元素的搜索目前有我,而不是难倒,但想知道是否有更好的解决方案。
集合的结构如下所示:
- Element (A)
- Element (A1)
- Element (A1.1)
- Element (A2)
- Element (B)
- Element (B1)
- Element (B1.1)
- Element (B1.2)
- Element (C)
- Element (C1)
- Element (C2)
- Element (C3)
目前我正在使用递归来搜索特定Attributes
的每个顶级(A,B,C)Element
的{{1}}字典。如果我在顶级KeyValuePair
找不到它,我会以同样的方式开始搜索其Element
集合(1,1.1,2,2.1,n等)。
我很好奇的是,如果有更好的方法来实现对这些对象的搜索,或者在这种情况下递归是更好的答案,如果我应该像我现在那样实现搜索,那么top - &gt;孩子 - &gt;孩子 - &gt;等等或者我是否应该首先搜索所有顶级的其他方式?
我可以,并且使用TPL并行搜索每个顶级(A,B,C)是否合理?
答案 0 :(得分:1)
递归是实现树搜索的一种方法,您可以按深度优先顺序访问元素。您可以使用堆栈数据结构来存储您需要访问的树的节点,从而使用循环而不是递归来实现相同的算法。
如果您使用相同的算法与队列而不是堆栈,搜索将按照先呼吸顺序进行。
在这两种情况下,通用算法如下所示:
var nodes = ... // some collection of nodes
nodes.Add(root);
while (nodes.Count != 0) {
var current = nodes.Remove ... // Take the current node from the collection.
foreach (var child in current.ChildCollection) {
nodes.Add(child);
}
// Process the current node
if (current.Attributes ...) {
...
}
}
请注意,该算法不是递归的:它使用nodes
的显式集合来保存搜索的当前状态,而递归实现使用调用堆栈来实现相同的目的。如果nodes
是Stack<Element>
,则搜索将在depth-first order中进行;如果nodes
是Queue<Element>
,则搜索会在breadth-first order进行。
答案 1 :(得分:0)
您可以以不同的方式重复使用专为遍历进行设计的现有组件,例如NETFx IEnumerable.Traverse Extension Method。它允许您首先深度或广度。它允许您首先遍历可枚举的树,深度或广度。
获取展平的可枚举目录的示例:
IEnumerable<DirectoryInfo> directories = ... ;
IEnumerable<DirectoryInfo> allDirsFlattened = directories.Traverse(TraverseKind.BreadthFirst, dir => dir.EnumerateDirectories());
foreach (DirectoryInfo directoryInfo in allDirsFlattened)
{
...
}
对于BreadhFirst,它在内部使用Queue<T>,而对于DepthFirst,它在内部使用Stack<T>。
不是遍历节点并行,除非遍历是资源要求,否则在此级别使用并行是不合适的。但这取决于具体情况。
答案 2 :(得分:0)
我从某处抓住了这一点,它不是我的,但我无法提供它的链接。这个类使用树形视图进行递归搜索,看起来应该为你做同样的事情。
public static class SOExtension
{
public static IEnumerable<TreeNode> FlattenTree(this TreeView tv)
{
return FlattenTree(tv.Nodes);
}
public static IEnumerable<TreeNode> FlattenTree(this TreeNodeCollection coll)
{
return coll.Cast<TreeNode>()
.Concat(coll.Cast<TreeNode>()
.SelectMany(x => FlattenTree(x.Nodes)));
}
}
我找到了这个链接 - 它很容易使用。看一看。 Is there a method for searching for TreeNode.Text field in TreeView.Nodes collection?