递归检索二分搜索树的子集

时间:2018-11-19 13:02:53

标签: java recursion tree binary-tree binary-search-tree

对于我正在使用私有字段实现的二叉树对象

X key;
Y value;
Tree<X,Y> left;
Tree<X,Y> right;

我有一个方法public Tree<X,Y> subset(X startKey, X endKey),该方法需要返回一个Tree,其中包括具有startKey的节点和具有endKey的节点之间的所有键及其对应的值。还需要使用递归来执行此方法。

我遇到的问题是,我找不到一种方法来获取以endKey结尾的树(可能看起来像LinkedList),而没有包括endKey.left和{ {1}}。我认为我应该首先从根的左树或右树上递归调用该方法,具体取决于startKey是大于还是小于根密钥,所以:

endKey.right

这将继续在树中导航,直到它到达包含键if (this.key.compareTo(startKey) < 0) this.right.subset(startKey, endKey); else if (this.key.compareTo(startKey > 0) this.right.subset(startKey, endKey); 的节点上为止。到那时,我将startKey复制到新树上,这样就可以避免编辑原始树。这个新树的节点以this为根,然后具有与原始树相同的子节点。

这就是我被困住的地方。我知道我必须处理的问题是导航到startKey,确保我停在那里并且不包含endKeyendKey.left,并且即使在方法是从递归调用中“放松”。我在想,如果我想在endKey.right停下来,则必须以某种方式保留对其父节点的引用,以便可以将父节点的左或右子节点设置为以便切断endKey的其余孩子。但是,由于我实际上没有节点对象,并且无法添加任何方法或构造函数,因此我不知道如何维护对父树的引用。我还不知道如何尝试将endKey保留为新树的根。

换句话说,我认为我已经设法获得了一个树的子集,该子集从较低级别开始并一直延伸到原始树的底部。如何递归地消除不需要的底部的子代并返回新的子集?

1 个答案:

答案 0 :(得分:0)

如果将其视为视图,则实际上并未将其剪切掉,而只是将方法限制为子集的范围。使用iterator()时,例如子图仅具有自己的Iterator实现,该实现从子图的下限开始,并在达到上限时返回hasNext() == false。用户不会注意到他实际上是在原始树上进行迭代,因为它完全被隐藏了。我希望这个例子能让您对此有所了解。

public interface Tree<X, Y> extends Iterable<Tree<X, Y>> {
    X getKey();
    X getValue();
    Tree<X, Y> floor(X key);
    Tree<X, Y> ceiling(X key);
    Tree<X, Y> subTree(X lo, X hi);
    // ...
}

public class TreeImpl<X, Y> implements Tree<X, Y> {
    final X key;
    Y value;
    TreeImpl<X, Y> left, right;

    public TreeImpl(X key, Y value) {
        this.key = key;
        this.value = value;
    }

    @Override
    public Iterator<Tree<X, Y>> iterator() {
        return new TreeItr();
    }

    // Iterator starting at the most left to the most right;
    private class TreeItr implements Iterator<Tree<X, Y>> {
        // ...
    }

    @Override
    public Tree<X, Y> subTree(X lo, X hi) {
        return new SubTree<>(this, lo, hi);
    }

    private static class SubTree<X, Y> implements Tree<X, Y> {
        final Tree<X, Y> backing;
        final X lo, hi;

        public SubTree(Tree<X, Y> backing, X lo, X hi) {
            this.backing = backing;
            this.lo = lo;
            this.hi = hi;
        }

        @Override
        public Iterator<Tree<X, Y>> iterator() {
            return new SubTreeItr(backing.ceiling(lo), backing.floor(hi))
        }

        // Iterator starting at 'from' and returning 'hasNext() == false' after 'to'
        // has returned
        private class SubTreeItr implements Iterator<Tree<X, Y>> {
            final Tree<X, Y> from, to;

            public SubTreeItr(Tree<X, Y> from, Tree<X, Y> to) {
                this.from = from;
                this.to = to;
            }

            //...
        }

        @Override
        public Tree<X, Y> subTree(X lo, X hi) {
            // Check if lo > this.lo && hi < this.hi
            return new SubTree<>(backing, lo, hi);
        }
    }
}