订购二元搜索树的轮换

时间:2013-02-25 03:56:07

标签: algorithm rotation binary-search-tree

假设我有一个平衡的二叉搜索树来表示这个有序序列。

A<B<C<D<E<F<G<H

给定其中一个元素,例如F,如何有效地转换树,以便结果表示这个有序序列?

F<G<H<A<B<C<D<E?

从F到右边的元素被移动到所有其他元素的前面。请注意,这与通常意义上的“树旋转”无关。这里的旋转发生在元素的顺序意义上。它与双向链表的“旋转”含义相同。例如,如果问题是关于双链表而不是二进制搜索树,那么解决方案很简单:

E.next := null
F.prev := null
H.next := A
A.prev := H

平衡二叉搜索树是否有效的解决方案?

实施说明:

首先看起来似乎即使有一个有效的算法,它也没什么用,因为必须更新移动元素的值以保留二叉搜索树的不变量(左孩子较小,右孩子较大)。但是,情况并非如此,因为在模运算模 N 中,可以在不改变节点值的情况下在固定时间内固定顺序。假设节点的顺序定义如下:

(A < B) if and only if ((A.value - C) mod N) < ((B.value - C) mod N)

此处, A.value B.value C [0,N]范围内的整数。对此的图形解释是我们有一个 N 点遍布的圆圈,我们对这些点进行排序,使 C 为最小点,然后是 C +1 C + 2 等,最多 C +(N-1),这是最重要的一点。

无论如何,在将 F 和所有后续元素移到前面后,通过更改 C 可以轻松修复树不变量:

C := F.value

1 个答案:

答案 0 :(得分:2)

通常,这不能在少于O(N)的时间内完成。经过一些小改动后,余额可以在O(log N)中恢复,但是切割整个分支并将其粘贴到其他地方是一个很大的变化。

提取n个元素并逐个插入它们需要O(n log N)。如果n很大,重建整个树是值得的,这可以在O(N)时间内完成。

也就是说,您可以将有序遍历的整个序列视为循环列表。您可以维护一个指向您认为是“第一个”元素的指针,只需要在将某些元素从“结束”移动到“开头”时更改它,反之亦然。如果要按顺序访问序列,只需从指向的元素(“第一个”)开始,继续按顺序遍历并环绕树的末尾。在访问最右边的元素后,继续最左边的元素。当你再次到达“第一个”元素时停止。