递归集合搜索

时间:2013-07-13 13:17:11

标签: c# search recursion task-parallel-library icollection

我有一个对象集合(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)是否合理?

3 个答案:

答案 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的显式集合来保存搜索的当前状态,而递归实现使用调用堆栈来实现相同的目的。如果nodesStack<Element>,则搜索将在depth-first order中进行;如果nodesQueue<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?