平衡二叉树AVL

对于有N个节点的二叉排序树,我们期望其高度是LogN,但实际情况往往事与愿违。在极端情况下,比如在生成二叉排序树时,其插入的序列是个有序数列,此时的二叉树结构类似于一个链表,各个操作的时间与链表的操作无异。因此,通过某种方法使得二叉树左右子树深度一样或者相差不大是有意义和必要的。这就是平衡二叉树,也叫AVL树。

1.AVL树定义

平衡二叉树要么是空树,要么满足以下性质

  1. 左右子树的高度之差的绝对值不超过1;
  2. 左右子树也分别为AVL树。
    例如下图中,左边是AVL树,但是右边的不是,因为左子树的高度为2,右边为0,相差为2,在节点19处产生了不平衡。
    这里写图片描述

2.AVL树的平衡过程

二叉排序树在插入节点或者删除节点时,可能导致树的不平衡,此时需要通过某些操作来平衡二叉树。一般来说,有4中不平衡的情况,如下图:
这里写图片描述
①LL:左左,插入或者删除一个节点导致根节点的左子树高度比根的右子树的高度大2.
②RR:右右,插入或者删除一个节点导致根节点的右子树高度比根的左子树的高度大2.
③LR:左右,插入或者删除一个节点导致根节点的左子树高度比根的右子树的高度大2.
④RL:右左,插入或者删除一个节点导致根节点的右子树高度比根的左子树的高度大2.

2.1 LL或者RR

这两种情况是对称的,所以处理办法也是相对称的,通过一次旋转即可,如下图:
这里写图片描述

2.2 RL或者LR

这两种情况稍微复杂,但也是对称的,通过两次旋转即可,如下图:
这里写图片描述

3.代码

class AVLTree 
{
public:
    AVLTree(){}
    int data;
    int height;
    AVLTree *left, *right;
};

static int getHeight(AVLTree* node)
{
    return node->height;
}

static int getMax(int a, int b)
{
    return (a>b)?a:b;
}

AVLTree* left_left_rotate(AVLTree* k1)
{
    AVLTree *k2 = k1->left;
    k2->right = k1;
    k1->left = k2->right;

    k1->height = getMax(getHeight(k1->left),getHeight(k1->right))+1;
    k2->height = getMax(getHeight(k2->left),getHeight(k1))+1;

    return k2;
}

AVLTree* right_right_rotate(AVLTree* k1)
{
    AVLTree *k2 = k1->right;
    k2->left = k1;
    k1->right = k2->left;

    k1->height = getMax(getHeight(k1->right),getHeight(k1->left))+1;
    k2->height = getMax(getHeight(k2->right),getHeight(k1))+1;

    return k2;
}

AVLTree* left_right_rotate(AVLTree *k3)
{
    k3->left = right_right_rotate(k3->left);
    return left_left_rotate(k3);
}

AVLTree* right_left_rotate(AVLTree *k3)
{
    k3->right = left_left_rotate(k3->left);
    return right_right_rotate(k3);
}

4.插入节点

void insertNode(AVLTree* x,int key)
{
    if(x == NULL)
    {
        x = (AVLTree*)malloc(sizeof(AVLTree));
        if(x == NULL)
            printf("malloc failure!");
        else
        {
            x->data = key;
            x->height = 1;
            x->left = x->right = NULL;
        }
    }
    else
    {
        if(key > x->data)
        {
            ///右子树
            insertNode(x->right,key);
            if(getHeight(x->right)-getHeight(x->left)>1)
            {
                //RR
                if(key>x->right->data)
                    x = right_right_rotate(x);
                else//RL
                    x = right_left_rotate(x);
            }

        }
        else if(key < x->data)
        {
            ///左子树
            insertNode(x->left,key);
            if(getHeight(x->left)-getHeight(x->right)>1)
            {
                //LR
                if(key > x->left->data)
                    x = left_right_rotate(x);
                else//LL
                    x = left_left_rotate(x);
            }
        }
        else//插入值在树中已存在
            printf("值%d已存在",key);
    }
    x->height = getMax(getHeight(x->left),getHeight(x->right))+1;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

冯Jungle

您的支持是对我最大的鼓励

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

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

打赏作者

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

抵扣说明:

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

余额充值