C++代码,数据结构-平衡二叉树

AVL的插入建立算法,用到了递归,且要分好几种一般情况来解决各类情况。

总体分为四种情况,

LL型,LR型,RR型,RL型;

下面说一下LL 型,和LR型的情况,另外两种的情况与这两种为镜像关系;

LL型,LR型,设结点A,A是离插入点最近,且平衡因子为1,(结点平衡因子左子树深度减去右子树深度)

LL型

在A的左子树根节点的左子树上插入结点F,导致A结点的平衡因子又1变到了2, 所以对A结点要进行右旋操作

代码中的

R_rotate(a)
具体实现过程如图

《C++代码,数据结构-平衡二叉树》           ————A结点右旋——————–>《C++代码,数据结构-平衡二叉树》

F点为插入点,

注意:在代码中还有修改相关点的平衡因子

LR型:

在A的左子树根节点的右子树上插入结点F,导致A结点的平衡因子又1变到了2,所以对、要进行两次操作,先左旋,再右旋

代码中的:

    L_rotata(A->lchild);
    R_rotate(A);

LR再细分有两种情况

插入点为左孩子还是右孩子

代码中的体现是

        Bstree rd=lc->rchild;
    switch(rd->bf){
case LH:T->bf=RH; lc->bf=EH;break;
case EH:T->bf=lc->bf=EH;break;
case RH:T->bf=EH;lc->bf=LH;break;
    }

关系到相关结点平衡因子的修改。如有疑惑可以看下面的图

1.插入点为左孩子

《C++代码,数据结构-平衡二叉树》–先对B结点进行左旋-,—>《C++代码,数据结构-平衡二叉树》—-对A右旋—–> 《C++代码,数据结构-平衡二叉树》                                                             变成了LL的情况,在对A进行右旋即可 

但是不要忘了修改相关结点的平衡因子。

2.插入点为右孩子

《C++代码,数据结构-平衡二叉树》–先对B结点进行左旋-,—>《C++代码,数据结构-平衡二叉树》–对A右旋—–>《C++代码,数据结构-平衡二叉树》

                                                                          变成了LL的情况,在对A进行右旋即可 

但是不要忘了修改相关结点的平衡因子。

下面是完整代码,没有写删除代码,和查询代码,

#include<iostream>
#include<fstream>
#include<cstdlib>
#include<queue>
using namespace std;

//平衡二叉树的建立,遍历,,

struct Bstnode{
int data;
int bf;//平衡因子
Bstnode*lchild,*rchild;
};
typedef Bstnode * Bstree;

#define LH +1
#define EH 0
#define RH -1

void R_rotate(Bstree &p){//右旋,
Bstree lc=p->lchild;
p->lchild=lc->rchild;
lc->rchild=p;
p=lc;
}
void L_rotata(Bstree &p){//左旋,
Bstree rc=p->rchild;
p->rchild=rc->lchild;
rc->lchild=p;
p=rc;


}





void Leftbalance(Bstree &T){//左子树的平衡处理
Bstree lc=T->lchild;
switch(lc->bf){//LL的情况
case LH:
    T->bf=lc->bf=EH;
    R_rotate(T);break;

case RH://LR的情况,同时针对rd上的不同情况,进行对T,lc的平衡因子的设置
        Bstree rd=lc->rchild;
    switch(rd->bf){
case LH:T->bf=RH; lc->bf=EH;break;
case EH:T->bf=lc->bf=EH;break;
case RH:T->bf=EH;lc->bf=LH;break;
    }
    rd->bf=EH;
    L_rotata(T->lchild);
    R_rotate(T);
}


}


void Rightbalance(Bstree &T)//右子树的平衡处理,与左子树的平衡处理类似
{
Bstree rc=T->rchild;
switch (rc->bf){
case RH:
    T->bf=rc->bf=EH;
    L_rotata(T);break;
case LH:
   Bstree ld=rc->lchild;
    switch(ld->bf){
case LH:
    T->bf=EH; rc->bf=RH;break;
case EH:
    T->bf=rc->bf=EH;break;
case RH:
    T->bf=LH; rc->bf=EH;break;

    }
    ld->bf=EH;
    R_rotate(T->rchild);
    L_rotata(T);
}

}


bool InsertAVL(Bstree &T,int e,bool &taller){
if(!T){//此结点为空,则插入,并设置该点平衡因子为0,taller为true,长高了
    T=new Bstnode;
    T->data =e; T->lchild=T->rchild=NULL;  T->bf=EH; taller=true;
}
else
{
    if(e==T->data){taller =false; return 0;}//已经存在,不插入,返回0;
if(e<T->data){//如果e小于本结点,则继续在左子树搜索,
if(!InsertAVL(T->lchild,e,taller))return 0;//未插入,返回0;
if(taller)//已经插入到了左子树,则要检查平衡度,
{                                  //注意!检查平衡度是由下往上的,哪个结点的失去平衡,则对该结点进行平衡操作
switch(T->bf){
case LH:   //本结点本来左比右高,现在插入了,所以要做平衡处理
        Leftbalance(T);taller=false; break;
case EH:  //本来等高,现在插入了,所以本结点平衡因子为1;taller 设为false ,进入下一个递归的时候,不需要在检查平衡;
    T->bf=LH; taller=true;break;
case RH://本来右边高,现在插入了,所以本结点平衡因子为0;taller 设为false ,进入下一个递归的时候,不需要在检查平衡;
    T->bf =EH; taller=false; break;
    }

}

}
else{//在右子树中查找
    if(!InsertAVL(T->rchild,e,taller))return 0;//未插入,返回0;
    if(taller){ //同上,检查平衡
        switch(T->bf){
    case LH://本来左高,现在等高
        T->bf=EH; taller=false; break;
    case EH://本来平衡,现在右增高了,所以本结点平衡因子为-1.taller为true,进入下一个递归是继续检查平衡,
        T->bf=RH;taller=true;break;
    case RH://本来右高,现在右又增高了,所以失去平衡,对该节点进行平衡处理
        Rightbalance(T);taller=false;break;
        }
    }
}


}

return 1;
}




void visit(int c){
cout<<c<<"   ";}


void cengcitravel(Bstree T){
    Bstree p;
    queue<Bstree>sq;
    sq.push(T);
while(!sq.empty()){
 p=sq.front();
 visit(p->data);
if(p->lchild)sq.push(p->lchild);
if(p->rchild)sq.push(p->rchild);
 sq.pop();
}

}


int main(){

    int x;
Bstree T=NULL;
bool f=false;
while(cin>>x){
   InsertAVL(T,x,f);
}
cin.clear();
cengcitravel(T);//输出序列
cout<<endl;

return 0;
}

    原文作者:平衡二叉树
    原文地址: https://blog.csdn.net/y519476132/article/details/19497207
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞