C/C++实现AVL树(二叉平衡搜索树)
一开始以为很复杂很可怕,后来自己想了一下其实也没那么可怕,无非就是左右子树的顺序调换而已。
有关AVL的旋转的原理就不再说明,不懂自行百度查书了解旋转原理。
以下是部分代码实现AVL树
首先是树的结构的构建
struct tree
{
struct tree* ls; //左儿子
struct tree* rs; //右儿子
int siz,con,data,height; //大小,内容,数据,高度
};
typedef struct tree stu;
typedef struct tree* ptr;
下面是旋转的代码实现
1.左单旋与右单旋
什么时候单旋不再说明了,自行百度查书了解各种情况。
void left(ptr* now){ //左旋
ptr tmp=(*now)->rs; //其实本质就是左右儿子的替换
(*now)->rs=tmp->ls;
tmp->ls=*now;
tmp->siz=(*now)->siz;
pushup(*now),pushup(tmp);
*now=tmp;
return;
}
void right(ptr* now){ //右旋
ptr tmp=(*now)->ls;
(*now)->ls=*now;
tmp->siz=(*now)->siz;
pushup(*now),pushup(tmp);
*now=tmp;
return;
}
2.插入、平衡、刷新过程
平衡这一部分的代码是AVL的核心
其实也就是比普通二叉搜索树多了一个平衡的操作而已
写出二叉搜索树,再加上平衡操作就行了
总的来说就是插入->平衡->刷新
void ins(ptr* now,int num) //其实仔细分辨的话,也只是比二叉搜索树多了一些判断和平衡而已
{
if (*now==NULL)
{
*now=(ptr)malloc(sizeof(stu));
(*now)->siz=(*now)->con=1;
(*now)->data=num,(*now)->height=0;
(*now)->ls=(*now)->rs=NULL; return;
}
if ((*now)->data==num)
{
(*now)->con++;
pushup(*now); return;
}
if ((*now)->data>num) ins(&(*now)->ls,num);
else ins(&(*now)->rs,num);
pushup(*now); balance(now); return;
}
void balance(ptr *now) //进行平衡的操作 对于不同情况的调用
{
if (*now==NULL) return;
if (h((*now)->ls)-h((*now)->rs)==2)
{
if (h((*now)->ls->ls)>h((*now)->ls->rs)) right(now);
else left(&(*now)->ls),right(now); return;
}
if (h((*now)->rs)-h((*now)->ls)==2)
{
if (h((*now)->rs->rs)>h((*now)->rs->ls)) left(now);
else right(&(*now)->rs),left(now); return;
}
return;
}
void pushup(ptr now){ //进行重新刷新 相当于树的重建过程
if(now==NULL) return; //刷新当前树的高度,数据内容等
now->height=1;
now->siz=now->con;
now->siz+=size(now->ls);
now->siz+=size(now->rs);
if(h(now->ls)>h(now->ls))
now->height+=h(now->ls);
else now->height+=h(now->rs);
return;
}
3.删除节点后的平衡
void del(ptr* now,int num)
{
if (*now==NULL) return;
if ((*now)->data==num)
{
if ((*now)->con>1) (*now)->con--;
else
{
ptr cng=*now;
if ((*now)->ls==NULL) *now=(*now)->rs,free(cng);
else if ((*now)->rs==NULL) *now=(*now)->ls,free(cng);
else
{
cng=(*now)->rs;
while (cng->ls) cng=cng->ls;
(*now)->data=cng->data;
(*now)->con=cng->con,cng->con=1;
del(&(*now)->rs,cng->data);
}
}
}
else
{
if ((*now)->data>num) del(&(*now)->ls,num);
else del(&(*now)->rs,num);
}
pushup(*now); balance(now); return;
}
4.打印AVL树的结点
1.前序遍历
void print(ptr p)
{
printf("data:%d,con:%d,",p->data,p->con);
printf("siz:%d,h:%d ",p->siz,p->height);
return;
}
void printfst(ptr now)
{
if (now)
{
print(now);
if (now->ls) printfst(now->ls);
if (now->rs) printfst(now->rs);
}
else printf("NULL");
return;
}
2.中序遍历
void printmid(ptr now)
{
if (now)
{
if (now->ls) printmid(now->ls);
print(now);
if (now->rs) printmid(now->rs);
}
else printf("NULL");
return;
}
3.后序遍历
void printlst(ptr now)
{
if (now)
{
if (now->ls) printlst(now->ls);
if (now->rs) printlst(now->rs);
print(now);
}
else printf("NULL");
return;
}
5.总结
这个是链表实现的AVL树,后期会补充上数组实现AVL树,
总的来说,并不算太难,比起复杂的图的递归,这个确实比较明确,就是旋转->平衡->刷新的过程。
往后也会补充上双旋的过程。
也欢迎大家一起学习交流。