📜  Day-Stout-Warren 算法平衡给定的二叉搜索树

📅  最后修改于: 2022-05-13 01:56:05.421000             🧑  作者: Mango

Day-Stout-Warren 算法平衡给定的二叉搜索树

给定一个不平衡的二叉搜索树(BST),任务是在线性时间内将其转换为平衡的 BST,并且不使用辅助空间。

例子:

方法:此场景中使用的算法是Day-Stout-Warren 算法。形成的平衡树将是一棵完全二叉树。请按照以下步骤执行算法。

  • Step 1 :利用右旋的概念,通过中序遍历,将给定的BST转换成链表(右链表)。这种形式的 BST 被称为骨干或藤蔓。这个阶段的运行时间是线性的,不需要额外的空间。
    该函数的编码方式是,它执行所有所需的右旋转以展平 BST,并在最后返回 BST 中的节点数。
  • 第 2 步:使用公式h = log2(N+1) [N 是节点总数] 计算BST 的高度,其中所有级别将被完全填充。并使用高度计算可以适合该高度的节点数m = pow(2, h)-1 。 [h 是高度,直到所有级别都被节点完全填充]
    N 和 m的差值 (diff) 是平衡完全二叉树最后一级的节点数量。
  • 然后将第一步中获得的藤蔓从其根部左旋不同时间。然后将上述修改后的树左旋转 m/2, m/4, m/8 。 . .根据算法,直到 m 大于 0 的次数

插图:

下面是上述方法的实现。

C++
// C++ code to balance BST using DSW algorithm.
#include 
using namespace std;
  
// Defining the structure for TreeNode.
struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode()
        : val(0)
        , left(NULL)
        , right(NULL)
    {
    }
    TreeNode(int x)
        : val(x)
        , left(NULL)
        , right(NULL)
    {
    }
    TreeNode(int x, TreeNode* left, 
             TreeNode* right)
        : val(x)
        , left(left)
        , right(right)
    {
    }
};
  
// Function to convert input BST 
// to right linked list
// known as vine or backbone.
int bstToVine(TreeNode* grand)
{
    int count = 0;
  
    // Make tmp pointer to traverse 
    // and right flatten the given BST.
    TreeNode* tmp = grand->right;
  
    // Traverse until tmp becomes NULL
    while (tmp) {
          
        // If left exist for node 
        // pointed by tmp then 
        // right rotate it.
        if (tmp->left) {
            TreeNode* oldTmp = tmp;
            tmp = tmp->left;
            oldTmp->left = tmp->right;
            tmp->right = oldTmp;
            grand->right = tmp;
        }
  
        // If left dont exists
        // add 1 to count and 
        // traverse further right to
        // flatten remaining BST.
        else {
            count++;
            grand = tmp;
            tmp = tmp->right;
        }
    }
  
    return count;
}
  
// Function to compress given tree
// with its root as grand->right.
void compress(TreeNode* grand, int m)
{
    // Make tmp pointer to traverse 
    // and compress the given BST.
    TreeNode* tmp = grand->right;
  
    // Traverse and left-rotate root m times 
    // to compress given vine form of BST.
    for (int i = 0; i < m; i++) {
        TreeNode* oldTmp = tmp;
        tmp = tmp->right;
        grand->right = tmp;
        oldTmp->right = tmp->left;
        tmp->left = oldTmp;
        grand = tmp;
        tmp = tmp->right;
    }
}
  
// Function to implement the algorithm
TreeNode* balanceBST(TreeNode* root)
{
    // create dummy node with value 0
    TreeNode* grand = new TreeNode(0);
  
    // assign the right of dummy node as our input BST
    grand->right = root;
  
    // get the number of nodes in input BST and
    // simultaneously convert it into right linked list.
    int count = bstToVine(grand);
  
    // gets the height of tree in which all levels
    // are completely filled.
    int h = log2(count + 1);
  
    // get number of nodes until second last level
    int m = pow(2, h) - 1;
  
    // Left rotate for excess nodes at last level
    compress(grand, count - m);
  
    // Left rotation till m becomes 0
    // Step is done as mentioned in algo to
    // make BST balanced.
    for (m = m / 2; m > 0; m /= 2) {
        compress(grand, m);
    }
  
    // return the balanced tree
    return grand->right;
}
  
// Function to print preorder traversal
// of Binary tree.
void preorderTraversal(TreeNode* root)
{
    if (!root)
        return; 
    cout << root->val << " ";
    preorderTraversal(root->left); 
    preorderTraversal(root->right);
    return;
}
  
// Driver code
int main()
{
    TreeNode* root = new TreeNode(10);
    root->left = new TreeNode(5);
    root->left->left = new TreeNode(2);
    root->left->left->left 
        = new TreeNode(1);
      
    // Function call to implement 
    // Day-Stout-Warren algorithm
    root = balanceBST(root);
      
    // To print the preorder traversal of BST
    preorderTraversal(root);
  
    return 0;
}


Javascript



输出
5 2 1 10 

时间复杂度: O(N) 其中 N 是 BST 中的节点总数
辅助空间: O(1)