【问题标题】:Order rotation of a binary search tree二叉搜索树的顺序旋转
【发布时间】:2013-02-26 14:50:19
【问题描述】:

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

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.valueB.valueC[0,N)范围内的整数时间>。对此的图形解释是,我们有一个散布有 N 个点的圆,我们对这些点进行排序,使得 C 是最少的点,然后是 C +1C+2等,直到C+(N-1),这是最大的点。

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

C := F.value

【问题讨论】:

  • 请定义“高效”。您可以在 O(N) 中重建整棵树。这够好吗?如果没有,你真的需要改变树吗?指向“第一个”元素的指针不好吗?
  • 还取决于树的平衡方式,即它是伸展树还是红黑树,或者它是否由于其他原因恰好以当前形式平衡。
  • @comocomocomocomo 高效意味着 log(n)。您关于保留第一个元素指针的想法应该可行。要按顺序迭代树,您将从“第一个”元素开始,在末尾环绕,并在再次遇到“第一个”元素之前结束。你应该发布一个答案:)
  • @antti.huima 这是一棵 AVL 树,但我希望该解决方案适用于各种平衡树。
  • @AmbrozBizjak:我会的:-)

标签: algorithm rotation binary-search-tree


【解决方案1】:

一般来说,这不能在少于 O(N) 的时间内完成。稍作改动后可以在 O(log N) 内恢复平衡,但是将整个分支剪切并粘贴到其他地方是一个很大的变化。

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-25
    相关资源
    最近更新 更多