我在AVL Tree Wikipedia page注意到以下评论:
“如果每个节点另外记录其子树的大小(包括它自己及其后代),那么也可以通过索引在O(log n)时间内检索节点。”
我用Google搜索并找到了一些提到accessing by index的地方,但似乎找不到人们会写的算法的解释。
非常感谢
[更新]谢谢大家。如果发现@templatetypedef与@ user448810 links中的一个结合起来特别有帮助。特别是这个剪辑:
“这两个函数的关键是节点的索引是它的左子节点的大小。只要我们通过它的左子节点下降树,我们只需要取节点的索引。但是当我们我必须通过正确的孩子向下移动树,我们必须调整大小以包括我们排除的树的一半。“
因为我的实现是不可变的,所以在重新平衡时我不需要做任何额外的工作,因为每个节点在构造时计算它的大小(与链接的方案相同)
我的最终实施最终成为:
class Node<K,V> implements AVLTree<K,V> { ...
public V index(int i) {
if (left.size() == i) return value;
if (i < left.size()) return left.index(i);
return right.index(i - left.size() - 1);
}
}
class Empty<K,V> implements AVLTree<K,V> { ...
public V index(int i) { throw new IndexOutOfBoundsException();}
}
与其他实现略有不同,如果您认为我有错误,请告诉我们!
答案 0 :(得分:10)
这种结构背后的一般思想是采用现有的BST并通过在左子树中存储节点数来扩充每个节点。完成此操作后,您可以使用以下递归算法在树中查找第n个节点:
这需要时间O(h),其中h是树的高度。在AVL树中,这个O(log n)。在CLRS中,这种结构被探索应用于红/黑树,他们称这些树为“秩序统计树”。
您必须在树旋转期间添加一些额外的逻辑来调整左子树中缓存的元素数量,但这并不是特别困难。
希望这有帮助!