范围树实现

时间:2015-05-28 05:14:32

标签: algorithm data-structures range-tree

我试图实现一个范围树,但我真的很困惑,这是我的文字:

enter image description here

现在假设我有一棵这样的树:

enter image description here

我想找到14到19之间的点。V_Split在这里是17,并且从17移动到14,根据算法,我应该报告17的正确的子树,即23和19.但是23不是14到19之间。我该怎么办?

如果我不考虑17,那么17本身不会被报道。然后如果我想找到12到19之间的分数,那么就不会包括14个!

1 个答案:

答案 0 :(得分:1)

前段时间我实施了维基百科Range Tree文章(范围查询部分)中描述的步骤,这些步骤与您的文字类似。主要的想法是找到vsplit点然后二进制搜索vsplit的左右孩子,抓住范围内的所有""我们移动时的节点。

我想保持数据结构(TreeNode)非常基本,以便更容易理解(因为我没有看到需要将每个节点存储为文章建议的叶子?)。无论如何,下面你可以找到我班级的主要方法,它包含一步一步解释的一般想法。请随意从我的github repository中获取整个代码,但我建议您先尝试自己编写getLeftNodes()/ getRightNodes()代码。

    /**
     * Range trees can be used to find the set of points that lay inside a given
     * interval. To report the points that lie in the interval [x1, x2], we
     * start by searching for x1 and x2.
     * 
     * The following method will use a regular balanced binary search tree for
     * this purpose. More info in https://en.wikipedia.org/wiki/Range_tree
     * 
     * @param x1
     *            Low (start) range position
     * @param x2
     *            High (end) range position
     * @param root
     *            A balanced binary search tree root
     * @return
     */
    public HashSet<Integer> getNodesInRange(int x1, int x2, TreeNode root) {
        if (x1 >= x2) {
            throw new IllegalArgumentException("Range error: x1 must be less than x2");
        }

        // At some vertex in the tree, the search paths to x1 and x2 will
        // diverge. Let vsplit be the last vertex that these two search paths
        // have in common.
        TreeNode vsplit = root;
        while (vsplit != null) {
            if (x1 < vsplit.data && x2 < vsplit.data) {
                vsplit = vsplit.left;
            } else if (x1 > vsplit.data && x2 > vsplit.data) {
                vsplit = vsplit.right;
            } else {
                break;
            }
        }

        // Report the value stored at vsplit if it is inside the query interval.
        HashSet<Integer> nodesInRange = new HashSet<>();
        if (vsplit == null) {
            return nodesInRange;
        } else if (inRange(vsplit.data, x1, x2)) {
            nodesInRange.add(vsplit.data);
        }

        // Continue searching for x1 in the range tree (vSplit to x1).
        getLeftNodes(x1, x2, nodesInRange, vsplit.left);
        // Continue searching for x2 in the range tree (vSplit to x2).
        getRightNodes(x1, x2, nodesInRange, vsplit.right);

        return nodesInRange;
    }

此实现的时间复杂度目标应该是O(log(n)),因为我们正在进行三次二进制搜索(vsplit + left + right),每次搜索都采用O(log(n)),因此它应该是非常有效的太

编码这有助于我理解范围树的总体思路(在代码挑战中非常有用),我希望它能为你做同样的事情。

注意:我确信有更简单的实施(以及更有效的实施)!