二叉搜索树的间隔与排序数组一样快

时间:2015-08-31 02:18:35

标签: algorithm performance data-structures

目前,我正在为我的大学项目实施Java的BST。众所周知,BST非常适合在平衡树中搜索单个单元,即O(log n)。

但是如何在值ab之间执行搜索? (a< b)

我们说我有这棵树

│               ┌── 125
│           ┌── 122
│           │   └── 120
│       ┌── 117
│       │   │   ┌── 113
│       │   └── 112
│       │       └── 108
│   ┌── 86
│   │   │   ┌── 85
│   │   └── 72
└── 59
    │           ┌── 56
    │       ┌── 52
    │   ┌── 47
    │   │   │   ┌── 43
    │   │   └── 39
    │   │       │   ┌── 38
    │   │       └── 36
    └── 28
        │       ┌── 18
        │   ┌── 15
        └── 2
            └── 1

我想创建一个方法range(a,b),以便在ab之间返回值。 (注意:树中不需要ab!)

例如:range(53,112)将返回56,59,72,85,86,108,112

这是我的伪代码

/* recursive method */
range(a,b)
    range(a,b,root);

/* helper method */
range(a,b,node)
    if (a <= node.value <= b)
        if (node.left != null) and (node.value != a)
            range(a,b,node.left)

        print node.value

        if (node.right != null) and (node.value != b)
            range(a,b,node.right)

    else if node.value < a
        if (node.right != null)
            range(a,b,node.right)

    else // node.value > b
        if (node.left != null)
            range(a,b,node.left)

但我觉得我的方法比较慢。

例如,在排序数组中,我们必须在ab上执行二进制搜索并获取它们各自的索引。之后,我们从a的索引迭代到b的索引。

BST在搜索多个值时执行速度是否正常?是否有可能将我的算法提高到与排序数组一样快?

1 个答案:

答案 0 :(得分:1)

根据您返回结果的方式,排序数组可能具有无需在任何地方复制结果的巨大优势。只是将指针+长度视图返回到数组中比将范围的另一个副本放入另一个缓冲区要快得多且缓存更友好。树总是必须从树中复制元素。即使你确实需要一个副本(修改或其他),memcpy比走树要快得多。

如果您可以在行走树时动态处理(例如,您正在使用print),这不是问题。

我似乎总是在谷歌搜索之前写出答案。结果是trees to answer range queries are a thing。显然,它通常用于2D或3D范围(例如,每个点都有x和y坐标),您可以对排序的数组执行此操作。我认为这是因为尽管它尽可能高效,但它并不像将指针+长度窗口返回到排序数组那样有效!

我不打算从维基百科复制/粘贴整个算法,只是聪明的想法:

  

为了报告区间[x1,x2]中的点,我们从中开始   搜索x1和x2。在树的某个顶点,搜索路径   到x1和x2会发散

这就是您如何有效地检测您知道将在您的范围内的整个子树,请参阅维基百科和/或谷歌&#34;树范围查询&#34;有很多细节。

我之前的谷歌搜索观察是你可以避免比较,只是走一些子树。在您的示例中,86的左子树保证全部在范围内,因为我们知道它们全部&gt; 59和&lt; 86,这比[a..b]更严格。我没有想过要找到这种特殊情况的方法,这种情况不会比节省的成本更高。