将节点旋转到BST的根

时间:2013-11-07 02:00:54

标签: c++ binary-search-tree

所以我的功能是在BST中旋转我的节点:

void BST::rotate_with_left_child(BNode *&t){

    BNode *t1 = t->left;
    t->left = t1->right;
    t1->right = t;
    t->node_height = max(height(t->left),height(t->right))+1;
    t1->node_height = max(height(t1->left),t->node_height)+1;
    t = t1;

}

void BST::double_rotate_with_left_child(BNode *&t){

    rotate_with_right_child(t->left);
    rotate_with_left_child(t);

}

void BST::rotate_with_right_child(BNode *&t){

    BNode *t1 = t->right;
    t->right = t1->left;
    t1->left = t;
    t->node_height = max(height(t->right),height(t->left))+1;
    t1->node_height = max(height(t1->right),t->node_height)+1;
    t = t1;

}

void BST::double_rotate_with_right_child(BNode *&t){

    rotate_with_left_child(t->right);
    rotate_with_right_child(t);

}

并说我发现了一个我想要旋转到树根的节点。我将如何编写一个函数来执行此操作?

1 个答案:

答案 0 :(得分:1)

注意:以下代码根本未经过测试。它只是说明了这些想法。代码一直在底层。

假设:

  • 节点没有父链接,非根节点无法判断它是父节点的左子节点还是右子节点。否则,算法可以略微简化。
  • 一个节点有一个左侧链接和一个右侧链接,这可以从您的代码中看出来。
  • 此算法不会考虑最终树是否平衡。如果您需要平衡,那么您可以停止阅读此答案想看看Splay Trees:http://en.wikipedia.org/wiki/Splay_tree

我假设您通过某种搜索例程获取节点。现在,我们的想法就是维持:

  1. 您在搜索中看到的一堆节点
  2. 搜索中遍历的链接方向
  3. 例如,给定这棵树:

                 15
                /  \
               2   35
                  /  \
                 28   42
                /  \
              19    31
    

    我们搜索了树内的密钥19。现在,我们希望将19一直旋转到顶部。

    NodeStack,从堆栈底部到顶部的一堆节点:[15, 35, 28, 19]< - 堆栈顶部

    DirStack,遍历了一堆链接路线:[RIGHT, LEFT, LEFT]< - 堆栈顶部

    我们假设搜索命中此处。所以我们要做的第一件事是检索NodeStack的最顶层元素,这是我们想要旋转到顶部的节点。在这种情况下,它是具有键19的节点。完成此步骤后,两个堆栈都显示为:

    NodeStack[15, 35, 28]< - 堆栈顶部

    DirStack[RIGHT, LEFT, LEFT]< - 堆栈顶部

    接下来,主循环运行直到DirStack为空。我们从两个堆栈中弹出一个元素。从NodeStack弹出的元素是我们希望旋转到顶部的节点的父节点,从DirStack弹出的元素表示从刚刚弹出的节点到未来根节点的链接方向

    在循环的第一次迭代中,我们有节点28和链接方向LEFT,因此节点19是节点28的左子节点。

    应该不难看出我们应该向刚刚弹出的方向旋转,所以我们应该在方向为RIGHT的情况下向左旋转父节点,并且如果方向旋转父节点是LEFT。由于此处的方向为LEFT,因此我们将父节点28 向右旋转。这可以通过调用节点rotate_with_left_child上的28函数来实现。

    树成为

                 15
                /  \
               2   35
                  /  \
                 19   42
                  \
                   28
                    \
                     31
    

    请注意28成为了正确的孩子,因此这是正确的轮换。我很确定这是正确的术语。由于维基百科现在已经关闭,我无法验证这一点,但这个问题表明我使用了正确的术语:

    Code with explanation for binary tree rotation (left OR right)

    现在的筹码状态:

    NodeStack[15, 35]< - 堆栈顶部

    DirStack[RIGHT, LEFT]< - 堆栈顶部

    堆栈不为空,因此我们从两个堆栈中弹出35LEFT。我们使用节点35上的 rotate_with_left_child 函数执行正确的旋转,以获取此树:

                 15
                /  \
               2    19
                     \
                     35
                    /  \
                   28  42
                    \
                     31
    
    

    我们的节点现在更接近成为root。立即堆叠:

    NodeStack[15]

    DirStack[RIGHT]

    我们弹出节点15和方向RIGHT。现在,我们使用节点rotate_with_right_child上的15函数执行左旋转,然后我们获取最后一棵树:

                 19
                /  \
               15   35
              /     / \
             2     28 42
                    \
                     31
    
    

    Tadah!我们现在完成了。这是代码,使用STL中的std::stack

    // NOTE: None of the code here is tested, so some errors are expected.
    
    // Used to indicate direction of links traversed during the search
    enum Direction {
      LEFT, RIGHT
    };
    
    // This function rotates the node at the top of nodeStack to the root of the tree.
    // It assumes that the nodeStack is non-empty, and that nodeStack has one more
    // element than dirStack
    //
    // nodeStack - stack of nodes encountered during search
    // dirStack  - direction of links traversed during search
    void rotate_to_top(stack<BSTNode *>& nodeStack, stack<Direction>& dirStack) {
        // remove the future root node. actually this assignment is not needed
        // NOTE: You might also want to check if the nodeStack is empty before doing this
        BSTNode* root = nodeStack.top();
        nodeStack.pop();
    
        // main loop. this is done until the dirStack is empty
        while (!dirStack.empty()) {
            Direction d = dirStack.top();
            dirStack.pop();
            BSTNode *par = nodeStack.top();
            nodeStack.top();
            // perform the proper rotation
            if (d == LEFT) {
                rotate_with_left_child(par);
            } else {
                rotate_with_right_child(par);
            }
        }
    }
    

    希望有帮助=)