平衡二叉树的算法

Posted

tags:

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

参考技术A

Size Balanced Tree(简称SBT)是一自平衡二叉查找树,是在计算机科学中用到的一种数据结构。它是由中国广东中山纪念中学的陈启峰发明的。陈启峰于2006年底完成论文《Size Balanced Tree》,并在2007年的全国青少年信息学奥林匹克竞赛冬令营中发表。由于SBT的拼写很容易找到中文谐音,它常被中国的信息学竞赛选手和ACM/ICPC选手们戏称为“傻B树”、“Super BT”等。相比红黑树、AVL树等自平衡二叉查找树,SBT更易于实现。据陈启峰在论文中称,SBT是“目前为止速度最快的高级二叉搜索树”。SBT能在O(log n)的时间内完成所有二叉搜索树(BST)的相关操作,而与普通二叉搜索树相比,SBT仅仅加入了简洁的核心操作Maintain。由于SBT赖以保持平衡的是size域而不是其他“无用”的域,它可以很方便地实现动态顺序统计中的select和rank操作。

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

平衡二叉查找树,也被称为高度平衡树。相比于”二叉查找树”,它的特点是: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;

}


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

平衡二叉树的构建

平衡二叉树算法时间复杂度分析与优点

什么是平衡二叉树

算法题-平衡二叉树

算法素颜:玩平衡二叉树就像跷跷板一样简单!

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