AVL树的建立解析含代码(C++)
AVL树
AVL树是平衡二叉树,它可以尽可能创建“枝繁叶茂”的树,防止树枝过长过少。二叉树搜索中,会引入ASL平均查找长度的概念,表示查找所有节点的比较次数平均值。平衡二叉树的ASL相较而言较小。
思路
AVL树就是比较各个节点左右子树的深度差,当差值等于2时就需要对树结构进行改变。改变的方式有左旋、右旋、左右旋以及右左旋。判断旋转方式是看导致深度差值的结点在哪。左旋是顺时针旋转相关结点,右旋为逆时针旋转相关结点。左右旋及右左旋为左旋、右旋的组合,左右旋先右旋后左旋。
如下面图的示例:



以上图片来自陈越《数据结构》一书。
关于旋转结点的代码不是很难,RL旋和LR旋为各是两个单旋的组合,L旋和R旋的思路又都一样。因此只要搞懂一个方向的单旋即可。注意单旋时旋转结点的子结点位置的改变。具体的看代码。
代码
#include <iostream>
using namespace std;
/*avl平衡树的建立,需要判断一个节点左右两子树的深度差,差值小于2视为平衡*/
typedef struct node{
int data;
node* lchild;
node* rchild;
int height;
}*bitTree;
int max(int a,int b)
{//用于比较子树大小
return a>b?a:b;
}
int getHeight(bitTree T)
{//获取树的高度
int lnum,rnum,count;
if(T){
lnum = getHeight(T->lchild);
rnum = getHeight(T->rchild);
count = lnum>rnum?lnum:rnum;//比较左右子树的高度取最大值
return (count+1);
}
}
bitTree singleleftRotation(bitTree T)//左旋
{
bitTree B = new node;
B = T->lchild;
T->lchild = B->rchild;
B->rchild = T;
T->height = max(getHeight(T->lchild),getHeight(T->rchild))+1;
B->height = max(getHeight(B->lchild),T->height)+1;
return B;
}
bitTree singlerightRotation(bitTree T)
{
bitTree B = T->rchild;
T->rchild = B->lchild;
B->lchild = T;
T->height = max(getHeight(T->lchild),getHeight(T->rchild))+1;
B->height = max(getHeight(B->rchild),T->height)+1;
}
bitTree doubleleftrightRotation(bitTree T)
{
T->lchild = singlerightRotation(T->lchild);
return singleleftRotation(T);
}
bitTree doublerightleftRotation(bitTree T)
{
T->rchild = singleleftRotation(T->lchild);
return singlerightRotation(T);
}
bitTree insert(bitTree &T,int x)
{//AVL树在插入的过程中不断判断
if(!T)//插入一个空树
{
T = new node;
T->data = x;
T->lchild = T->rchild = NULL;
T->height = 1;//这里树高的初值不重要,后续的高度都会做左右子树高度对比重新取值
}
else if(x<T->data){//插入值在左子树中
T->lchild = insert(T->lchild,x);
//对旋的判断就是看其插入的位置
if(getHeight(T->lchild)-getHeight(T->rchild)==2){
if(x<T->lchild->data)//需要L旋
T = singleleftRotation(T);
else//左右旋
T = doubleleftrightRotation(T);
}
}
else if(x>T->data){//插入值在右子树中
T->rchild = insert(T->rchild,x);
//对旋的判断就是看其插入的位置
if(getHeight(T->lchild)-getHeight(T->rchild)==2){
if(x>T->rchild->data)//需要R旋
T = singlerightRotation(T);
else//RL旋
T = doublerightleftRotation(T);
}
}
T->height = max(getHeight(T->lchild),getHeight(T->rchild))+1;//插入了新值,树的高度加一
return T;
}
int display(bitTree T)
{//先序遍历
if(T!=NULL)
{
display(T->lchild);
cout<<T->data<<" ";
display(T->rchild);
}
}
int main()
{
/*
示例生成二叉树:
18
/ \
10 20
/ \ / \
9 11 19 22
*/
bitTree T;
int a[7] = {9,11,19,22,18,10,20};
for(int i = 0;i<7;i++)
insert(T,a[i]);
display(T);
//输出9 10 11 18 19 20 22
}
注意点
结点的单旋需要传入的结点为第一个深度不平衡的结点。多旋则是先对不平衡结点的下一个子节点单旋,后对不平衡结点再做一次单旋。
下面以RL旋做一个例子


浙公网安备 33010602011771号