【问题标题】:What are some alternatives to recursive search algorithms?递归搜索算法有哪些替代方案?
【发布时间】:2011-12-30 00:47:21
【问题描述】:

我正在寻找我一直在研究的深度搜索算法的替代方案。我的代码有点长,无法在此处发布,但我已经编写了一个简化版本来捕获重要方面。首先,我创建了一个名为“BranchNode”的对象,该对象包含一些值以及一组其他“BranchNode”对象。

class BranchNode : IComparable<BranchNode>
{
    public BranchNode(int depth, int parentValue, Random rnd)
    {
        _nodeDelta = rnd.Next(-100, 100);
        _depth = depth + 1;
        leafValue = parentValue + _nodeDelta;

        if (depth < 10)
        {
            int children = rnd.Next(1, 10);
            branchNodes = new BranchNode[children];
            for (int i = 0; i < children; i++)
            {
                branchNodes[i] = new BranchNode(_depth, leafValue, rnd);
            }
        }
    }

    public int CompareTo(BranchNode other)
    {
        return other.leafValue.CompareTo(this.leafValue);
    }


    private int _nodeDelta;
    public BranchNode[] branchNodes;
    private int _depth;
    public int leafValue;


}

在我的实际程序中,我从其他地方获取数据……但对于这个示例,我只是将一个 Random 对象的实例传递到我用来为每个 BranchNode 生成值的行中。 .. 我还手动创建了 10 的深度,而我的实际数据将有任意数量的代。

作为对我的目标的快速解释,_nodeDelta 包含一个分配给每个 BranchNode 的值。每个实例还维护一个叶子值,它等于当前 BranchNode 的 _nodeDelta 与它所有祖先的 _nodeDelta 之和。我正在尝试找到没有子节点的 BranchNode 的最大叶子值。

目前,我正在递归遍历层次结构,搜索其子 BranchNodes 数组为空的 BranchNodes(又名:“无子”BranchNode),然后将其叶值与当前最高叶值的叶值进行比较。如果它更大,它将成为基准并继续搜索,直到它查看所有 BranchNode。

如果有帮助,我可以发布我的递归搜索算法,但它非常标准,并且运行良好。正如预期的那样,我的问题是,对于较大的层次结构,我的算法需要很长时间才能遍历整个结构。

我想知道我是否有任何其他可以研究的选项可能会产生更快的结果...具体来说,我一直在尝试围绕 linq,但我什至不确定它是否已构建做我正在寻找的东西,或者如果它会更快。还有其他我应该调查的事情吗?

【问题讨论】:

  • 所有递归算法都可以使用循环展开和完成。
  • 虽然在这种情况下,Linq 可能不是该任务的正确工具,但如果你真的愿意,可以express recursion in Linq
  • 数据实际上是一个对象层次结构还是您将数据作为 xml... 或者您如何获取数据?
  • 提高对大型数据集的查询的搜索时间的标准方法是构建另一个称为“索引”的数据结构,可以快速搜索。谷歌和必应实际上不会在几毫秒内搜索整个互联网;他们在几毫秒内搜索整个互联网的索引。我给你的建议:建立一个索引;搜索它。
  • 您是否可以从对象中引用 BranchNode 的父节点,还是只维护子节点数组?如果你能穿越两个方向,我可能会有一些想法。

标签: c# linq recursion


【解决方案1】:

也许您想研究另一种数据索引结构:Here

这始终取决于您对数据所做的工作,但如果您为存储分层形式的每个元素分配一个唯一 ID,并为您存储的内容创建索引,那么您的优化将比微观更有意义- 优化你所做的部分。

此外,这也为搜索算法提供了一种非常不同的范例,它不使用递归,但会为 ID 和可能的索引增加额外的内存。

【讨论】:

  • 虽然我使用了来自各种答案的一些技术,但使用单独的索引似乎是最有益的。
  • 我很高兴这项技术对您有所帮助,因为它一直在帮助我。我正在链接的这种特殊的索引方式有一个特殊的好处:您只需 1 个低成本查询即可获取包含所有子节点(以及子节点的子节点等)的节点。虽然它的写入成本较高,所以它用于写入比读取稀疏的情况
【解决方案2】:

如果必须访问所有叶节点,则无法加快搜索速度:无论如何它都会遍历所有节点。一个典型的加速树搜索的技巧是以某种特殊的方式组织它们来简化树的搜索。例如,通过构建二叉搜索树,您可以搜索O(Log(N))。您还可以在非叶节点中存储一些有用的值,以后可以从中构造搜索查询的答案。

例如,您可以决定将 _bestLeaf “指向”存储到当前子树下所有叶子中 _nodeDelta 最高的叶子。如果您这样做,您的搜索将变为O(1) 查找。但是,您的插入和删除将变得更加昂贵,因为您需要在返回根目录的路上更新多达 Log-b(N) 个项目,使用新的 _bestLeafb 是您的树的分支因子)。

【讨论】:

  • 在过去,我们的分支因子已经达到了接近 25 的平均值,所以我认为必须在生成中增加如此大量的开销会抵消很大的收益。总成本将以“增长”我们的数据的时间以及搜索所需的时间来衡量。我将尝试这种方法,只是为了看看它的整体比较。我会在阅读并尝试一些基准测试后回来。
  • @Chronicide 大分支因子实际上很好:这意味着需要沿路径更新到根目录的次数更少。
  • 这只是表明在我做任何进一步的 cmets 之前,我会努力更好地理解你的答案。我相当肯定,根据我的数据的性质,构建二叉树是不可能的,我在增长数据时没有考虑过“搜索”......(至少,我认为你就是这样建议...我不得不承认,您的大部分答案仍然超出我的范围。)
【解决方案3】:

我认为您应该首先考虑的可能是离开 N-Tree 而成为二叉搜索树。

这意味着所有节点只有 2 个孩子,一个更大的孩子,一个更小的孩子。

从那里,我会说考虑平衡您的搜索树与红黑树或 AVL 之类的东西。这样,搜索你的树是 O(log n)。

以下是一些帮助您入门的链接:

http://en.wikipedia.org/wiki/Binary_search_tree http://en.wikipedia.org/wiki/AVL_tree http://en.wikipedia.org/wiki/Red-black_tree

现在,如果您对让每个节点能够拥有 N 个子节点的想法一无所知,那么您应该考虑以下几点:

  1. 考虑对您的子节点进行排序,以便您可以快速确定哪个具有最高的叶数。这样,当您进入一个新节点时,您可以检查一个子节点并快速确定是否值得递归检查它的子节点。
  2. 想一想可以快速从搜索中消除尽可能多的节点或尽早中断递归调用的方法。使用二叉搜索树,您可以通过始终只查看较大的孩子轻松找到最大的叶节点。如果树是平衡的,这可能会消除 N-log(n) 孩子。
  3. 考虑插入和删除节点。如果你花更多的时间在这里,你以后可以节省更多的时间

【讨论】:

    【解决方案4】:

    正如其他人所提到的,不同的数据结构可能是您想要的。

    如果您需要保持数据结构相同,则可以将递归展开为循环。虽然这种方法可能会快一点,但不会快几个数量级,但可能会占用更少的内存。

    【讨论】:

      猜你喜欢
      • 2011-03-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-25
      • 2010-09-07
      相关资源
      最近更新 更多