关于平衡二叉树的核心算法--旋转

Posted 666刘备深夜零食店

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于平衡二叉树的核心算法--旋转相关的知识,希望对你有一定的参考价值。

平衡二叉查找树,也被称为高度平衡树。相比于”二叉查找树”,它的特点是:AVL树中任何节点的两个子树的高度最大差别为1


如果在AVL树中插入或删除节点后,使得高度之差大于1。此时,AVL树的平衡状态就被破坏,它就不再是一棵二叉树;为了让它重新维持在一个平衡状态,就需要对其进行旋转处理。学AVL树,重点的地方也就是它的旋转算法

 旋转

这种失去平衡的可以概括为4种姿态:LL(左左)LR(左右)RR(右右)RL(右左)

关于平衡二叉树的核心算法--旋转

LL旋转

LL失去平衡的情况,可以通过一次旋转让AVL树恢复平衡。如下图:

关于平衡二叉树的核心算法--旋转

图中左边是旋转之前的树,右边是旋转之后的树。从中可以发现,旋转之后的树又变成了AVL树,而且该旋转只需要一次即可完成。

对于LL旋转,你可以这样理解为:LL旋转是围绕失去平衡的AVL根节点进行的,也就是节点k2;而且由于是LL情况,即左左情况,就用手抓着左孩子,即k1”使劲摇

关于平衡二叉树的核心算法--旋转

k1变成根节点,k2变成k1的右子树,”k1的右子树变成”k2的左子树

代码:

//LL左左旋转,返回值:旋转后的根节点

static avl_TreeNode* LL_rotation(avl_Tree T)

{

avl_Tree k2;

k2=T->lchild;

T->lchild=k2->rchild;

k2->rchild=T;

T->height=MAX(HEIGHT(T->lchild),HEIGHT(T->rchild))+1;

k2->height=MAX(HEIGHT(k2->lchild),k2->height)+1;

return k2;

}

RR旋转

理解了LL之后,RR就相当容易理解了。RR是与LL对称的情况!RR恢复平衡的旋转方法如下: 

关于平衡二叉树的核心算法--旋转

代码:

//RR右右旋转,返回值:旋转后的根节点

static avl_TreeNode* RR_rotation(avl_Tree T)

{

avl_Tree k3;

k3=T->rchild;

T->rchild=k3->lchild;

k3->lchild=T;


T->height=MAX(HEIGHT(T->lchild),HEIGHT(T->rchild))+1;

k3->height=MAX(HEIGHT(k3->rchild),k3->height)+1;

return k3;

}

LR旋转

LR失去平衡的情况,需要经过两次旋转才能让AVL树恢复平衡。如下图:

代码:

//LR旋转,先一次RR右右旋转,后LL左左旋转

static avl_TreeNode* LR_rotation(avl_Tree T)

{

T->lchild=RR_rotation(T->lchild);

return LL_rotation(T);

}

RL旋转

RL是与LR的对称情况!RL恢复平衡的旋转方法如下:

第一次旋转是围绕”k3”进行的”LL旋转,第二次是围绕”k1”进行的”RR旋转

代码:

//RL旋转,先LL左左旋转,后RR右右旋转

static avl_TreeNode* RL_rotation(avl_Tree T)

{

T->rchild=LL_rotation(T->rchild);

return RR_rotation(T);

}


插入节点:avl要在插入新结点后保证树的平衡性

avl_TreeNode* avl_insertNode(avl_Tree T,ElemType data)

{

if(T==NULL)

{

T=create_node(data,NULL,NULL);

//T=node;

if (T==NULL)

        {

            printf("ERROR: create avltree node failed! ");

            return NULL;

        }

}

else if(data<T->data)//小于根节点的话,插入左子树

T->lchild=avl_insertNode(T->lchild,data);//递归寻找插入节点的位置

//插入节点后可能引起二叉树的不平衡,所以要在此进行判断

if(HEIGHT(T->lchild)-HEIGHT(T->rchild)==2)

{//在这儿判断是LL还是LR

if(data<T->lchild->data)

{

//LL旋转

T=LL_rotation(T);

}

else

{

//LR旋转

T=LR_rotation(T);

}


}

}

else if(data>T->data)//大于根节点的话,插入右子树

{

T->rchild=avl_insertNode(T->rchild,data);//递归寻找插入节点的位置

//插入节点后可能引起二叉树的不平衡,所以要在此进行判断

if(HEIGHT(T->rchild)-HEIGHT(T->lchild)==2)

{

//在这儿判断是RR还是RL

    if(data>T->rchild->data)

{

   //RR旋转

      T=RR_rotation(T);

}

    else

{

   //RL旋转

   T=RL_rotation(T);

}

}

}

else//等于的话,提示不能相等

{

printf("节点不能相等");

//!要重新调整二叉树的深度

T->height=MAX(HEIGHT(T->lchild),HEIGHT(T->rchild))+1;

return T;

}


以上是关于关于平衡二叉树的核心算法--旋转的主要内容,如果未能解决你的问题,请参考以下文章

平衡二叉树的旋转

平衡二叉树的定义及基本操作(查找插入删除)及代码实现

平衡二叉树-AVL树(LLRRLRRL旋转)

数据结构—— 树:平衡二叉树

关于树的判定(满二叉树完全二叉树平衡二叉树相似二叉树等价二叉树)

了解数据结构之平衡二叉树 (AVL)-插入和删除