繁体   English   中英

修改二叉搜索树

[英]Modify a binary search tree

我正在尝试为二进制搜索树类编写一种方法来修改平衡的普通树,这使得该树仅在一侧具有节点。

从元素在不平衡树中出现的顺序来看,对我而言,顺序遍历(左,中,右)之间似乎存在某种关系。

迭代执行此操作的一种方法是使用树旋转。 这个想法是这样的:

  1. 如果根节点有左子节点,请向右旋转根节点。
  2. 否则,根节点没有左子节点。 向右下降并重复此过程。

用伪代码:

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM