平衡二叉树(AVL)的基本操作

AVL树的插入、创建和删除。主要是参考中国大学MOOC浙大版数据结构。

#include<bits/stdc++.h>
using namespace std;
/*
    AVL基本操作: 
        00)插入 
        01)创建 
        02)删除 
*/

/*
    AVL:
        1)是一棵空树
        2)具有下列性质的二叉树: 
            1)若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 
              若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 
              它的左、右子树也分别为二叉排序树。 
            2)每个结点的左右子树高度差最大为 1 
    特点:
        树高为log2(n)
*/

/*
    四种旋转
        1)单左旋转:
            破坏者在被破坏者(A)左孩子(B)的左子树上:B上升、A下沉、B右挂在A左上
            A->left = B->right; B->right = A; 
        2)单右选择: 
            破坏者在被破坏者(A)右孩子(B)的右孩子上:B上升、A下沉、B左挂在A右上
            A->right = B->left; B->left = A; 
        3)左右旋转: 
            破坏者在被破坏者(A)左孩子(B)的右子树上:
            B做单右旋转; A做单左旋转; 
        4)右左旋转:
            破坏者在被破坏者(A)右孩子(B)的左子树上:
            B做单左旋转; A做单右旋转;
*/
//AVL结点结构 
typedef class Node
{
    public:
        int val;
        Node *left;
        Node *right;
        int height;
        Node(){ left = right = NULL; }
        Node(int tval){ val = tval; left = right = NULL; }
} *AVL;

/*
    单左旋转:
        破坏者在被破坏者(A)左孩子(B)的左子树上:B上升、A下沉、B右挂在A左上
        A->left = B->right; B->right = A; 
        必须保证 A有左子树 
*/ 
AVL singleLeftRotation(AVL root)
{
    AVL rl = root->left;
    root->left = rl->right;
    rl->right = root;
    return rl;
}

/*
    单右旋转
        破坏者在被破坏者(A)右孩子(B)的右孩子上:B上升、A下沉、B左挂在A右上
        A->right = B->left; B->left = A;
        必须保证 A有右子树 
*/
AVL singleRightRotation(AVL root)
{
    AVL rr = root->right;
    root->right = rr->left;
    rr->left = root;
    return rr;
} 

/*
    左右旋转
        破坏者在被破坏者(A)左孩子(B)的右子树上:
        B做单右旋转; A做单左旋转;
        必须保证 A的左孩子和B的右孩子存在 
*/
AVL leftRightRotation(AVL root)
{
    root->left = singleRightRotation(root->left);
    return singleLeftRotation(root);
} 

/*
    右左旋转
        破坏者在被破坏者(A)右孩子(B)的左子树上:
        B做单左旋转; A做单右旋转;
*/
AVL rightLeftRotation(AVL root)
{
    root->right = singleLeftRotation(root->right);
    return singleLeftRotation(root);
} 
/*
    插入
        1)root为空时,插入结点
        2)root的值小于插入的值时: 
            递归到右子树
            退栈时如果  右子树的高度 - 左子树的高度 == 2: 
                插入右子树的左子树时,右左旋转
                插入右子树的右子树时,单右旋转
        3)root的值大于插入的值时:
            递归到左子树
            退栈时如果  左子树的高度 - 右子树的高度 == 2:
                插入左子树的左子树时,单左旋转
                插入左子树的右子树时,左右旋转
        4)更新 root的高度 
*/
int getHeight(Node *node){ return node == NULL ? 0 : node->height; }
AVL insert(AVL root, Node* node)
{
    if(root == NULL)
        root = node;
    else if(root->val < node->val){
        root->right = insert(root->right, node);    //出来之后 root->right一定不为空 
        if(getHeight(root->right) - getHeight(root->left) == 2)
            if(node->val < root->right->val)
                root = leftRightRotation(root);
            else
                root = singleRightRotation(root); 
    }
    else if(root->val > node->val){
        root->left = insert(root->left, node);
        if(getHeight(root->left) - getHeight(root->right) == 2)
            if(node->val < root->right->val)
                root = singleLeftRotation(root);
            else
                root = rightLeftRotation(root);
    }
    root->height = max(getHeight(root->left), getHeight(root->right)) + 1;
}

AVL create()
{
    int n, val;
    cin >> n;
    AVL root = NULL;
    for(int i = 0; i < n; i++)
    {
        cin >> val;
        root = insert(root, new Node(val));
    }
    return root;
}

/*
    删除
        1)root的值等于需删除的值时:右子树最小值替换root值,删除原右子树最小值
        2)root的值为空时:返回root
        3)root的值大于需删除的值时:递归左子树,退栈时若  右子树的高 - 左子树的高 == 2,判断右子树确定旋转方式 
        4)root的值小于需删除的值时:递归左子树,退栈时若  左子树的高 - 右子树的高 == 2,判断左子树确定旋转方式 
*/
AVL del(AVL root, int val)
{
    if(root == NULL)
        return root;
    else if(root->val < val){
        root->right = del(root->right, val);    //递归右子树 
        if(getHeight(root->left) - getHeight(root->right) == 2)
        {
            AVL temp = root->left;
            //temp的左子树高于右子树时:单左旋转
            //temp的右子树高于左子树时:左右旋转 
            if(getHeight(temp->left) > getHeight(temp->right))
                root = singleLeftRotation(root);
            else
                root = leftRightRotation(root);
        }
    }else if(root->val > val){
        root->left = del(root->left, val);
        if(getHeight(root->right) - getHeight(root->left) == 2)
        {
            AVL temp = root->right;
            //temp的左子树高于右子树时:右左旋转
            //temp的右子树高于左子树时:单右旋转 
            if(getHeight(temp->left) > getHeight(temp->right))
                root = rightLeftRotation(root);
            else
                root = singleRightRotation(root);
        }
    }else{
        //若左子树为空,右子树上升;右子树为空,左子树上升 
        //左右都不空时:用右子树最小值替换根的值,递归右子树删除原右子树最小值 
        if(root->left == NULL || root->right == NULL)
            return root->left == NULL ? root->right : root->left;
        AVL temp = root->right;
        while(temp->left != NULL)
            temp = temp->left;
        root->val = temp->val;
        root->right = del(root->right, root->val);
        return root;
    }
    //更新这次删除造成的高度的改变 
    root->height = max(getHeight(root->right), getHeight(root->left)) + 1;
}
void print_levelOrder_noLayered(AVL root)
{
    AVL pointer = root;
    int f = 0, t = 0;   //头、尾。模拟队列 
    AVL arr[1010];
    if(pointer != NULL)
        arr[t++] = pointer;
    while(t > f)
    {
        pointer = arr[f++];
        cout << pointer->val;
        if(pointer->left != NULL)
            arr[t++] = pointer->left;
        if(pointer->right != NULL)
            arr[t++] = pointer->right;
    }
}
int main()
{
    AVL root = create();
    print_levelOrder_noLayered(root);
    cout << endl;
    AVL d = del(root, 2);
    print_levelOrder_noLayered(d);
    return 0;
}
/*
    input:
        5
        2 4 1 3 0 
    AVL: 
            2
          1   4
        0    3
*/

猜你喜欢

转载自blog.csdn.net/qq_38206090/article/details/81708103
今日推荐