[英]Modify a binary search tree
我正在尝试为二进制搜索树类编写一种方法来修改平衡的普通树,这使得该树仅在一侧具有节点。
从元素在不平衡树中出现的顺序来看,对我而言,顺序遍历(左,中,右)之间似乎存在某种关系。
迭代执行此操作的一种方法是使用树旋转。 这个想法是这样的:
用伪代码:
Node finalRoot = null;
while (currNode != null) {
if (currNode.left != null) {
currNode = rotateRight(currNode);
} else {
if (finalRoot == null) finalRoot = currNode;
currNode = currNode.right;
}
}
return finalRoot;
此方法是从Day-Stout-Warren算法改编而来的,该算法是第一步。 它在时间O(n)中运行。
void unbalance(Node **pp) {
Node *p;
while ((p = *pp)) {
if (!p->left) {
pp = &p->right;
} else {
Node *tmp = p->left->right;
*pp = p->left;
p->left->right = p;
p->left = tmp;
}
}
}
...
Node *tree = ...;
unbalance(&tree);
该代码基于@templatetypedef的答案。 它使用指针到指针来避免finalRoot
节点(它也摆脱了finalRoot
,其唯一目的是避免finalRoot
调用者传递的原始根)。
这个想法是沿着最右边的树枝从树上走下来。 如果永远没有剩下的孩子,我们只输入if
语句的第一部分,然后不做任何事情就退出。
其余子树时使用else
部分。 在这种情况下,我们向右旋转树。
这具有从左子树上拉一个节点的效果,即我们的左子树现在小了一个节点。 我们重复此操作,直到左子树完全消失,然后再次进入if
的第一部分。 然后,我们进入剩下的右侧子树并重复整个过程。
修改链接列表或树的结构时,指针对指针通常很有用。 它们让我们直接使用原始指针,而不是复制它们。 在这种情况下,赋值*pp = ...
会在其他位置(一个pp
指向)修改指针。 这可以是原始根(由调用者传递),也可以是树中的right
指针之一(由pp = &p->right
)。 需要进行此重新定位,因为else
分支中的树旋转会乱序缠绕节点,因此以前作为子树的根的树会进一步向下移动,而先前的左节点会被拉起成为新的树根。 我们更新*pp
以保留指针向上的不变性(无论是调用者中的tree
变量还是父节点的right
成员)都指向子树的(新)根。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.