修改二叉搜索树

时间:2016-11-25 17:21:43

标签: c++ algorithm data-structures binary-search-tree

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

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

2 个答案:

答案 0 :(得分:1)

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

  1. 如果根节点有左子节点,则向右旋转根节点。
  2. 否则,根节点没有左子节点。下降并重复此过程。
  3. 在伪代码中:

    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)中运行。

答案 1 :(得分:1)

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,它的唯一目的是避免孤立调用者传入的原始根。)

这个想法是沿着最右边的树枝走下树。如果从未有任何留下的孩子,我们只输入if语句的第一部分并退出而不做任何事情。

当有左子树时,使用else部分。在那种情况下,我们向右旋转树。 animated tree rotation

这具有从左子树上拉出一个节点的效果,即我们的左子树现在是一个较小的节点。我们重复此操作,直到左子树完全消失为止,此时我们再次进入if的第一部分。然后我们转到剩下的右子树并重复整个事情。

在修改链表或树的结构时,指针指针通常很有用。它们让我们直接在原始指针上工作,而不是复制它们。在这种情况下,赋值*pp = ...会将指针修改为其他位置(pp指向的指针)。这可以是原始根(由调用者传入),也可以是树中的right个指针之一(由pp = &p->right设置)。需要进行此重新分配,因为else分支中的树旋转会使节点周围的位置混乱,因此以前作为子树根的内容会进一步向下移动,而前左节点会被拉起以成为新的根节点。我们更新*pp以保持指针更高的不变量(我们的调用者中的tree变量或父节点的right成员)指向的(新)根的子树。