平衡二叉树

平衡二叉树

1.平衡二叉树的定义

为了避免树的高度增长过快,降低二叉排序树的性能,我们规定在插入和删除节点时保证节点左右子树的高度差绝对值不超过一,这样的树称为平衡二叉树(也称AVL树),定义节点的左右子树的高度差为该节点的平衡因子,则此值只能为-1,0,1.

特性:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。

引用这里写图片描述

2.作用

我们知道,对于一般的二叉搜索树(Binary Search Tree),其期望高度(即为一棵平衡树时)为log2n,其各操作的时间复杂度(O(log2n))同时也由此而决定。但是,在某些极端的情况下(如在插入的序列是有序的时),二叉搜索树将退化成近似链或链,此时,其操作的时间复杂度将退化成线性的,即O(n)。我们可以通过随机化建立二叉搜索树来尽量的避免这种情况,但是在进行了多次的操作之后,由于在删除时,我们总是选择将待删除节点的后继代替它本身,这样就会造成总是右边的节点数目减少,以至于树向左偏沉。这同时也会造成树的平衡性受到破坏,提高它的操作的时间复杂度。

3.数据结构

struct node {
    int val;
    node *left, *right;
};

4.二叉平衡术的插入

1)RR旋转(左旋)

这里写图片描述


把B节点提起来,B的左挂到A的右,然后A再连到B的左,return
code:

node *rotateLeft(node *root) { //左旋 ,破坏者为右子树的右子树 
    node *t = root->right;
    root->right = t->left;
    t->left = root;
    return t;
}

2)LL旋转(右旋)

这里写图片描述


把B节点提起来,B的右挂到A的左,然后A再连到B的右,return
code:

node *rotateRight(node *root) { //右旋 ,破坏者为左子树的左子树 
    node *t = root->left;
    root->left = t->right;
    t->right = root;
    return t;
}

3)LR旋转(先左后右双旋)

这里写图片描述


code:

node *rotateLeftRight(node *root) { //‘麻烦节点 ’在左子树的右子树 
    root->left = rotateLeft(root->left);  
    return rotateRight(root);
}

4)RL旋转(先右后左双旋)

这里写图片描述


code:

node *rotateRightLeft(node *root) {
    root->right = rotateRight(root->right); // ‘麻烦节点 ’在右子树的左子树 
    return rotateLeft(root);
}

5.建立AVL树

1) 获取树的高度

int getHeight(node *root) {
    if(root == NULL) return 0;
    return max(getHeight(root->left), getHeight(root->right)) + 1;
}

2)插入结点并调整平衡

node *insert(node *root, int val) {  //建立 BST tree 并调整平衡,不能有相同节点 
    if(!root) {
        root = new node;
        root->val = val;
        root->left = root->right = NULL;
    } else if(val < root->val) {
        root->left = insert(root->left, val); //插入
        if(getHeight(root->left) - getHeight(root->right) ==2)
            root = val < root->left->val ? rotateRight(root) : rotateLeftRight(root);   //旋转调整平衡 
    } else {
        root->right = insert(root->right, val);//插入
        if(getHeight(root->left) - getHeight(root->right) == -2)
            root = val > root->right->val ? rotateLeft(root) : rotateRightLeft(root); //旋转调整平衡
    }
    return root;
}

6.完整代码

#include<iostream>
using namespace std;
struct node {
    int val;
    node *left, *right;
};
node *rotateLeft(node *root) { //左旋 ,破坏者为右子树的右子树 
    node *t = root->right;
    root->right = t->left;
    t->left = root;
    return t;
}
node *rotateRight(node *root) { //右旋 
    node *t = root->left;
    root->left = t->right;
    t->right = root;
    return t;
}
node *rotateLeftRight(node *root) { //‘麻烦节点 ’在左子树的右子树 
    root->left = rotateLeft(root->left); //LR旋转 
    return rotateRight(root);
}
node *rotateRightLeft(node *root) {
    root->right = rotateRight(root->right); // ‘麻烦节点 ’在右子树的左子树 
    return rotateLeft(root);//先对右子树右旋,在左旋 
}
int getHeight(node *root) {
    if(root == NULL) return 0;
    return max(getHeight(root->left), getHeight(root->right)) + 1;
}
node *insert(node *root, int val) {  
    if(root == NULL) {
        root = new node;
        root->val = val;
        root->left = root->right = NULL;
    } else if(val < root->val) {
        root->left = insert(root->left, val);
        if(getHeight(root->left) - getHeight(root->right) > 1)
            root = val < root->left->val ? rotateRight(root) : rotateLeftRight(root);
    } else {
        root->right = insert(root->right, val);
        if(getHeight(root->left) - getHeight(root->right) < -1)
            root = val > root->right->val ? rotateLeft(root) : rotateRightLeft(root); 
    }
    return root;
}

void PreOrder(node *root){
    node *T=root;
    if(T){
        cout<<T->val <<" ";
        PreOrder(root->left );
        PreOrder(root->right );
    }
}

void InOrder(node *root){
    node *T=root;
    if(T){
        InOrder(root->left );
        cout<<T->val <<" ";
        InOrder(root->right );
    }
}

int main() {
    int n, val;
    cin>>n;
    node *root = NULL;
    for(int i = 0; i < n; i++) {
        cin>>val;
        root = insert(root, val);
    }
    cout<<endl<<"先序遍历结果:"<<endl; 
    PreOrder(root);
    cout<<endl<<"中序遍历结果:"<<endl; 
    InOrder(root);
    cout<<endl<<"输入一个插入节点N:"<<endl;
    node *T;
    while(cin>>n){
        T=insert(root, n);
        cout<<endl<<"先序遍历结果:"<<endl; 
        PreOrder(T);
        cout<<endl<<"中序遍历结果:"<<endl; 
        InOrder(T);
        root=T;
        cout<<endl<<"输入一个插入节点N:"<<endl;
    }
    return 0;
}

由先序遍历和中序遍历可唯一确定一颗二叉树,且中序遍历可得到升序序列.
测试数据运行截图如下:

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZCAIHUI_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值