平衡二叉树的构造与实现

        平衡二叉树简称平衡树,是由Adelson-VelskiiLandis1962年首先提出的,所以又称为AVL树。若一棵二叉树的每个左右节点的高度差最多相差1,此二叉树即是平衡二叉树。把二叉树的每个节点的左子树减去右子树定义为该节点的平衡因子。二叉平衡树的平衡因子只能是10或者-1

        平衡二叉树是对二叉搜索树(又称为二叉排序树)的一种改进。二叉搜索树有一个缺点就是,树的结构是无法预料的,随意性很大,它只与节点的值和插入的顺序有关系,往往得到的是一个不平衡的二叉树。在最坏的情况下,可能得到的是一个单支二叉树,其高度和节点数相同,相当于一个单链表,对其正常的时间复杂度有O(log n)变成了O(n),从而丧失了二叉排序树的一些应该有的优点。

        当插入一个新的节点的时候,在普通的二叉树中不用考虑树的平衡因子,只要将大于根节点的值插入到右子树,小于节点的值插入到左子树,递归即可。而在平衡二叉树则不一样,在插入节点的时候,如果插入节点之后有一个节点的平衡因子要大于2或者小于-2的时候,他需要对其进行调整,现在只考虑插入到节点的左子树部分(右子树与此相同)。

平衡二叉树多用于查找数据,所以平衡二叉树又是颗二叉排序树。

那么如何创建一颗平衡二叉树呢?

创建平衡二叉树,我们采用依次插入节点的方式进行。而平衡二叉树上插入节点采用递归的方式进行。递归算法如下:

1      若该树为一空树,那么插入一个数据元素为e的新节点作为平衡二叉树的根节点,树的高度增加1

2      若待插入的数据元素e和平衡二叉树(BBST)的根节点的关键字相等,那么就不需要进行插入操作。

3      若待插入的元素e比平衡二叉树(BBST)的根节点的关键字小,而且在BBST的左子树中也不存在和e有相同关键字的节点,则将e插入在BBST的左子树上,并且当插入之后的左子树深度增加1时,分别就下列情况处理之。

(a)    BBST的根节点的平衡因子为-1(右子树的深度大于左子树的深度):则将根节点的平衡因子更改为0BBST的深度不变;

(b)    BBST的根节点的平衡因子为0(左右子树的深度相等):则将根节点的平衡因子修改为1BBST的深度增加1

(c)    BBST的根节点的平衡因子为1(左子树的深度大于右子树的深度):若BBST的左子树根节点的平衡因子为1,则需要进行单向右旋转平衡处理,并且在右旋处理后,将根节点和其右子树根节点的平衡因子更改为0,树的深度不变;

BBST的左子树根节点的平衡因子为-1,则需进行先向左,后向右的双向旋转平衡处理,并且在旋转处理之后,修改根节点和其左,右子树根节点的平衡因子,树的深度不变;

4      e的关键字大于BBST的根节点的关键字,而且在BBST的右子树中不存在和e有相同关键字的节点,则将e插入到BBST的右子树上,并且当插入之后的右子树深度加1时,分别就不同的情况处理之。

a      BBST的根节点的平衡因子是1(左子树的深度大于右子树的深度):则将根节点的平衡因子修改为0BBST的深度不变;

b      BBST的根节点的平衡因子是0(左右子树的深度相等):则将根节点的平衡因子修改为-1,树的深度加1

c      BBST的根节点的平衡因子为-1(右子树的深度大于左子树的深度):若BBST的右子树根节点的平衡因子为1,则需要进行两次选择,第一次先向右旋转,再向左旋转处理,并且在旋转处理之后,修改根节点和其左,右子树根节点的平衡因子,树的深度不变;

BBST的右子树根节点的平衡因子为1,则需要进行一次向左的旋转处理,并且在左旋之后,更新根节点和其左,右子树根节点的平衡因子,树的深度不变;

 运行结构如图:

《平衡二叉树的构造与实现》
实现代码如下:

#include <stdio.h>
#include <stdlib.h>
/************************************************************************/
/*                    平衡二叉树---AVL                                  */
/************************************************************************/
#define LH +1     //左高
#define EH  0     //等高
#define RH -1     //右高
/*二叉树的二叉链表结点结构定义*/
typedef int ElemType;
typedef struct BSTNode{
ElemType data;                            //结点数据
int bf;                                   //结点平衡因子
struct BSTNode *lchild,*rchild;           //左右孩子指针
}*PBSTree;
 
/* 对以p为根结点的二叉排序树做右旋处理 */
void R_Rotate(PBSTree* p)
{
PBSTree lc = (*p)->lchild;    //lc指向p的左子树根结点
(*p)->lchild = lc->rchild;    //lc的右子树挂接为p的左子树
lc->rchild = *p;
*p = lc;                      //p指向新的根结点
}
/* 对以p为根结点的二叉排序树做左旋处理 */
void L_Rotate(PBSTree* p)
{
PBSTree rc = (*p)->rchild;    //lr指向p的右子树根结点
(*p)->rchild = rc->lchild;    //lr的左子树挂接为p的右子树
rc->lchild = *p;
*p = rc;                      //p指向新的根结点
}
/* 对以指针T为根结点的二叉树做左平衡旋转处理,处理结束后,指针T指向新的根结点 */
void LeftBalance(PBSTree* T)
{
PBSTree lc,rd;
lc = (*T)->lchild;  //lc指向T的左子树根结点
switch (lc->bf)
{ //检查T的左子树的平衡因子
case LH:           //新结点插入到T的左孩子的左子树上,要做单右旋处理
(*T)->bf = lc->bf = EH;
R_Rotate(T);
break;
case RH:           //新结点插入到T的左孩子的右子树上,要做双旋处理
rd = lc->rchild;   //rd指向T的左孩子的右子树的根结点
switch(rd->bf)     //修改T及其左孩子的平衡因子
{           
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_Rotate(&(*T)->lchild);
R_Rotate(T);
break;
}
}
/* 对以指针T为根结点的二叉树做右平衡旋转处理,处理结束后,指针T指向新的根结点 */
void RightBalance(PBSTree* T)
{
PBSTree lc,rd;
lc= (*T)->rchild;
switch (lc->bf)
{
case RH:
(*T)->bf = lc->bf = EH;
L_Rotate(T);
break;
case LH:
rd = lc->lchild;
switch(rd->bf)
{
case LH:
(*T)->bf = EH;
lc->bf = RH;
break;
case EH:
(*T)->bf = lc->bf = EH;
break;
case RH:
(*T)->bf = EH;
lc->bf = LH;
break;
}
rd->bf = EH;
R_Rotate(&(*T)->rchild);
L_Rotate(T);
break;
}
}
 
int InsertAVL(PBSTree* T,ElemType e,bool* taller)
{
if ((*T)==NULL)
{
(*T)=(PBSTree)malloc(sizeof(BSTNode));
(*T)->bf = EH;
(*T)->data = e;
(*T)->lchild = NULL;
(*T)->rchild = NULL;
*taller = true;
}
else if (e == (*T)->data)
{
*taller = false;
return 0;
}
else if (e < (*T)->data)
{
if(!InsertAVL(&(*T)->lchild,e,taller))
return 0;
if(*taller)
{
switch ((*T)->bf)
{
case LH:
LeftBalance(T);
*taller = false;
break;
case  EH:
(*T)->bf = LH;
*taller = true;
break;
case RH:
(*T)->bf = EH;
*taller = false;
break;
}
}
}
else
{
if(!InsertAVL(&(*T)->rchild,e,taller))
return 0;
if (*taller)
{
switch ((*T)->bf)
{
case LH:
(*T)->bf = EH;
*taller = false;
break;
case EH:
(*T)->bf = RH;
*taller = true;
break;
case  RH:
RightBalance(T);
*taller = false;
break;
}
}
}
return 1;
}
 
bool FindNode(PBSTree root,ElemType e,PBSTree* pos)
{
PBSTree pt = root;
(*pos) = NULL;
printf("\n遍历查找记录:");
while(pt)
{    printf("%d\t",pt->data);
if (pt->data == e)
{
//找到节点,pos指向该节点并返回true
(*pos) = pt;
return true;
}
else if (pt->data>e)
{
pt = pt->lchild;
}
else
pt = pt->rchild;
}
return false;
}
void InorderTra(PBSTree root)//先序遍历平衡二叉树
{
if(root->lchild)
InorderTra(root->lchild);
printf("%d ",root->data);
if(root->rchild)
InorderTra(root->rchild);
}
 
int main()
{
int i,nArr[] = {1,23,45,34,98,9,4,35,23};
PBSTree root=NULL,pos;
bool taller;
for (i=0;i<9;i++)
{
InsertAVL(&root,nArr[i],&taller);
}
InorderTra(root);
if(FindNode(root,45,&pos))
printf("\n%d\n",pos->data);
else
printf("\nNot find this Node\n");
return 0;
}

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