平衡二叉树AVL

  对于二叉查找树,当插入节点时,在一些情况下,而二叉树会出现不平衡的状况,即将节点都插入到了二叉树的左子树上;使得二叉树的查找性能大打折扣,因此,为了解决了二叉查找树退化成链表的问题,引入了平衡二叉树。

平衡二叉树(AVL)

定义:

  平衡二叉树

1.左、右子树的高度差的绝对值小于等于1;

2.左、右子树也分别为平衡二叉树。

  平衡因子-将二叉树上节点的左子树减去右子树高度的值,称为该节点的平衡因子BF。

  最小不平衡子树-距离插入节点最近的,且以平衡因子的绝对值大于1的节点为根的子树。

typedef int TreeKeyType;

struct AvlNode
{
     TreeKeyType data;
     int height;               //结点所在高度
     AvlNode *left;
     AvlNode> *right;

     //构造函数
     AvlNode(Data) : data(Data), left(NULL), right(NULL), height(0){}
 };        

 

插入(可能导致失衡,须进行调整):

 

 void Insert(AvlNode *&t, TreeKeyType x)
 {
     if (t == NULL)
         t = new AvlNode(x);

  //插入到左子树
     else if (x < t->data)
     {
         Insert(t->left, x);

         //判断平衡情况,若左子树比右子树高导致不平衡
         if (GetHeight(t->left) - GetHeight(t->right) > 1)
         {
             if (x < t->left->data)
                 //向左子树插入左孩子导致失衡
                 RR(t);//右单旋转
             else
                 //向左子树插入右孩子导致失衡
                 LR(t);//先左后右旋转
         }
     }


     //插入到右子树
     else if (x > t->data)
     {
         Insert(t->right, x);

         if (GetHeight(t->right) - GetHeight(t->left) > 1)
         {
             if (x > t->right->data)
                 LL(t);
             elseRL(t);
         }
     }


     //数据重复,不进行插入  
     else
         return;

     //更新树的高度
     t->height = max(GetHeight(t->left), GetHeight(t->right)) + 1;
 }

 

1、左单旋转
  向右子树插入右孩子导致AVL失衡时,需要围绕最小失衡子树的根节点进行左单旋转。

 

void RR(AvlNode *& t)
 {
     AvlNode *q = t->right;//q指向t的右子树的根节点
     t->right = q->left;//q的左子树挂为t的右子树
     q->left = t;//t变为q的左子树
     t = q;

     t->height = max(GetHeight(t->left), GetHeight(t->right)) + 1;
 }

 

2、右单旋转

  向左子树插入左孩子导致AVL失衡时,需要围绕最小失衡子树的根节点进行右单旋转。

 

void LL(AvlNode *& t)
 {
     AvlNode *q = t->left;
     t->left = q->right;
     q->right = t;
     t = q;

     t->height = max(GetHeight(t->left), GetHeight(t->right)) + 1;
 }

 

3、先左旋后右旋
  在左子树上插入右孩子导致AVL树失衡时,需要进行先左旋后右旋。

 

 LR(AvlNode *& t)
 {
     //双旋转可以通过两次单旋转实现
     //对t的左结点进行RR旋转,再对根节点进行LL旋转
     RR(t->left);
     LL(t);
 }

 

4、先右旋后左旋
  在右子树上插入左孩子导致AVL树失衡时,需要进行先右旋后左旋。

void RL(AvlNode *& t)
 {
     LL(t->right);
     RR(t);
 }

 

删除

1、删除右子树的节点
  删除右子树的节点导致AVL树失衡,相当于在左子树插入新节点导致AVL树失衡,应进行右单旋转或先右旋后左旋。
2、删除左子树的节点
  删除左子树的节点导致AVL树失衡,相当于在右子树插入新节点导致AVL树失衡,应进行左单旋转或者先左旋后右旋。

AvlNode * FindMax(AvlNode *t) const
{
    if (t == NULL)
        return NULL;
    if (t->right == NULL)
        return t;
    return FindMax(t->right);
}


AvlNode * FindMin(AvlNode *t) const
{
    if (t == NULL)
        return NULL;
    if (t->left == NULL)
        return t;
    return FindMin(t->left);
}


int GetHeight(AvlNode *t)
{
    if (t == NULL)
        return -1;
    else
        return t->height;
}


bool Delete(AvlNode *&t, T x)
{
    //t为空 未找到要删除的结点
    if (t == NULL)
        return false;
    //找到了要删除的结点
    else if (t->data == x)
    {
        //左右子树都非空
        if (t->left != NULL && t->right != NULL)
        {//在高度更大的那个子树上进行删除操作

            //左子树高度大,删除左子树中值最大的结点,将其赋给根结点
            if (GetHeight(t->left) > GetHeight(t->right))
            {
                t->data = FindMax(t->left)->data;
                Delete(t->left, t->data);
            }
            else//右子树高度更大,删除右子树中值最小的结点,将其赋给根结点
            {
                t->data = FindMin(t->right)->data;
                Delete(t->right, t->data);
            }
        }
        else
        {//左右子树有一个不为空,直接用需要删除的结点的子结点替换即可
            AvlNode *old = t;
            t = t->left ? t->left: t->right;//t赋值为不空的子结点
            delete old;
        }
    }
    else if (x < t->data)//要删除的结点在左子树上
    {
        //递归删除左子树上的结点
        Delete(t->left, x);
        //判断是否仍然满足平衡条件
        if (GetHeight(t->right) - GetHeight(t->left) > 1)
        {
            if (GetHeight(t->right->left) > GetHeight(t->right->right))
            {
                //RL双旋转
                t = RL(t);
            }
            else
            {//RR单旋转
                t = RR(t);
            }
        }
        else//满足平衡条件 调整高度信息
        {
            t->height = max(GetHeight(t->left), GetHeight(t->right)) + 1;
        }
    }
    else//要删除的结点在右子树上
    {
        //递归删除右子树结点
        Delete(t->right, x);
        //判断平衡情况
        if (GetHeight(t->left) - GetHeight(t->right) > 1)
        {
            if (GetHeight(t->left->right) > GetHeight(t->left->left))
            {
                //LR双旋转
                t = LR(t);
            }
            else
            {
                //LL单旋转
                t = LL(t);
            }
        }
        else//满足平衡性 调整高度
        {
            t->height = max(GetHeight(t->left), GetHeight(t->right)) + 1;
        }
    }

    return true;
}

 

查找和遍历同二叉查找树

 

原文链接 https://www.cnblogs.com/zhangbaochong/p/5164994.html

posted @ 2021-03-16 20:09  封狼居胥!  阅读(139)  评论(0编辑  收藏  举报