平衡二叉树的算法
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了平衡二叉树的算法相关的知识,希望对你有一定的参考价值。
参考技术ASize 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;
}
以上是关于平衡二叉树的算法的主要内容,如果未能解决你的问题,请参考以下文章