平衡二叉树及其操作实现

时间:2021-09-28 17:31:52

[问题描述]

    实现平衡二叉排序树的创建、插入、删除、查询操作,并求出所构建平衡二叉排序树的平均查找长度ASL。

[基本要求] 

1)以二叉链表作为平衡二叉树的存储结构;

2)输入一个关键字序列,建立对应的平衡二叉树;

3)向平衡二叉树中插入一个结点(关键字);

4)从平衡二叉树中删除一个结点(关键字);

5)计算平衡二叉树的平均查找长度;

6)销毁平衡二叉树。

计算平衡二叉树的平均查找长度公示(n为结点数):

ALS=((n+1)/n)*(log10(n+1)/log10(2))-1;


#include<stdio.h>    
#include<stdlib.h>
#include<math.h>
#define LH 1 //左高
#define EH 0 //一样高
#define RH -1 //右高
#define TRUE 1
#define FALSE 0
typedef int Status ;
typedef bool Boolean ;
typedef struct BSTNode
{
int data;
int bf; //结点的平衡因子
struct BSTNode * lchild,* rchild; //左、右孩子指针
}BSTNode,*BSTree;


//以*p为根的二叉排序做右旋处理
void R_Rotate(BSTree &p)
{
BSTree lc=p->lchild ; //lc指向*p左子树根结点
p->lchild =lc->rchild ; //lc右子树挂接为*p左子树
lc->rchild =p; //p指向新的根结点
p=lc;
}//R_Rotate

//以*p为根的二叉排序做左旋处理
void L_Rotate(BSTree &p)
{
BSTree rc=p->rchild ; //rc指向*p右子树根结点
p->rchild =rc->lchild ; //rc左子树挂接为*p右子树
rc->lchild =p; //p指向新的根结点
p=rc;
}//L_Rotate

// 对二叉树T进行左平衡处理(LL型和LR型)
void LeftBalance(BSTree &T)
{
BSTree lc = T->lchild;
switch (lc->bf)
{
//LL型的只需要进行右旋操作
case LH:
//右旋之后根和左子树都的平衡的
T->bf=lc->bf = EH;
R_Rotate(T); //右旋操作
break;
//LR型的需要进行左旋操作,然后右旋操作
case RH:
BSTree rd = lc->rchild;
switch (rd->bf)
{ //修改*T及其左孩子的平衡因子
case LH:T->bf = RH; lc->bf = EH;break;
case EH:T->bf = EH; lc->bf = EH;break;
case RH:T->bf = EH; lc->bf = LH;break;
} //switch (rd->bf)
rd->bf = EH;
L_Rotate(T->lchild);
R_Rotate(T);
break;
} //switch (lc->bf)
} //LeftBalance

void RightBalance(BSTree & T)
{
BSTree rc = T->rchild;
switch (rc->bf)
{
//RR型只需要做左旋操作
case RH:
T->bf = EH;
rc->bf = EH;
L_Rotate(T); //左旋操作
break;
//RL型需要先做右旋操作,然后做左旋操作
case LH:
BSTree ld = rc->lchild;
switch (ld->bf)
{
case LH:T->bf = EH; rc->bf = RH;break;
case EH:T->bf = EH; rc->bf = EH;break;
case RH:T->bf = LH; rc->bf = EH;break;
} //switch (ld->bf)
ld->bf = EH;
R_Rotate(T->rchild);
L_Rotate(T);
break;
}//switch (rc->bf)
} //RightBalance

//把元素e插入平衡二叉树T中
Status InsertAVL(BSTree &T, int e, Boolean & taller)
{
if (!T)
{
T = (BSTree)malloc(sizeof(BSTNode));
T->rchild = NULL;
T->lchild = NULL;
T->data = e;
T->bf = EH;
taller = TRUE;
}
else
{
//该元素已经在平衡二叉树中存在了
if (e == T->data)
{
taller = FALSE;
return FALSE;
}
//插入左子树
else if (e < T->data)
{
if (!InsertAVL(T->lchild, e, taller)) return FALSE; //未插入
if (taller) //插入成功,并且树变高了
{
switch (T->bf)
{
case LH:
LeftBalance(T); taller = FALSE; break;
//平衡二叉树做完左平衡操作后
//树高没有变化,故taller = false
case EH:
T->bf = LH; taller = TRUE; break;
//原来是平衡的故插入一个元素后
//树高必然变高
case RH:
T->bf = EH;taller = FALSE; break;
//原来是右子树比左子树高,但是当向左子树中
//插入一个元素的时候,树变平衡了,故taller = false
} //switch (T->bf)
} //if (taller)
}
//插入右子树
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;
} // switch (T->bf)
} //if (taller)
} //else
} //else
return TRUE;
}//InsertAVL

//从平衡二叉树中删除一个结点(关键字)
Status DeleteAVL(BSTree &T, int key, Boolean &shorter)
{
if (!T)
{//没有关键字
shorter = FALSE;
printf("该平衡二叉树中无此关键字!\n");
return 0;
}
else
{
if (key==T->data) //找到了需要删除的结点
{
//如果该结点的lchild 和
//rchild 至少有一个为NULL
//则大功告成,否则请参照
//下方解释
BSTree q = T;
if (!T->lchild)//如果该结点的lchild 为NULL
{
q = T;
T = T->rchild;
free(q);
shorter = TRUE;
return TRUE;
}
else if (!T->rchild){//如果该结点的rchild 为 NULL
q = T;
T = T->lchild;//如果不是&(引用)的强大功能,这句话是没有意义的
free(q);
shorter = TRUE;
return TRUE;
}
else {
//删除一个左右孩子都不为空的结点
//使该结点的直接前驱p的data替换该结点的data
//然后改变key=p.data
BSTree s = T->lchild;
while (s->rchild)
s = s->rchild;
T->data = s->data;
key = s->data;
}
}
if (key<T->data)
{
if (!DeleteAVL(T->lchild, key, shorter)) return 0;
if (shorter)
{
switch(T->bf)
{
case LH:T->bf = EH; shorter = TRUE;break;
case EH:T->bf = RH; shorter = FALSE;break;
case RH:RightBalance(T);
if (T->rchild->bf == EH)
shorter = FALSE;
else
shorter = TRUE;break;
}//switch(T->bf)
}
}
else{
if (!DeleteAVL(T->rchild, key, shorter)) return 0;
if (shorter)
{
switch(T->bf)
{
case LH:LeftBalance(T);
if (T->lchild->bf == EH)
shorter = FALSE;
else
shorter = TRUE;break;
case EH:T->bf = LH; shorter = FALSE;break;
case RH:T->bf = EH; shorter = TRUE;break;
}
}
}
}
return 1;
}//DeleteAVL

//计算平衡二叉树的平均查找长度(查找关键字e)
Status SearchBST(BSTree & T, int e)
{
if (T ==NULL)
{
printf("该平衡二叉树中无此关键字!\n");
return NULL;
}
if (T->data == e)
{
return T->data;
}
else if (e< T->data)
{
return SearchBST(T->lchild, e);
}
else
{
return SearchBST(T->rchild, e);
}
}

//销毁平衡二叉树
void DestroyBST(BSTree & T)
{
if (NULL == T) return;
DestroyBST(T->lchild);
DestroyBST(T->rchild);
free(T);
}

//输出平衡二叉树中的所有的元素(小->大,中序遍历)
void PrintBST(BSTree & T)
{
if (NULL == T) return;
PrintBST(T->lchild);
printf("%d ",T->data);
PrintBST(T->rchild);
}

//7-统计树的叶子结点个数
Status CountLeafs(BSTree T)
{
int i,j;
if (T)
{
i=CountLeafs(T->lchild);
j=CountLeafs(T->rchild);
return i+j+1;
}
else
return 0;
}

//平均查找长度
float ASL(BSTree T)
{
float n;
float ALS;
n=CountLeafs(T);
ALS=((n+1)/n)*(log10(n+1)/log10(2))-1;
return ALS;
}

主函数:

void main()
{
BSTree T=NULL;
bool taller = false,shorter;
int n,a;float c;
printf("请输入数据 ,输入0结束:\n");
while(scanf("%d",&n))
{
if(n==0) break;
else InsertAVL(T,n,taller);
}
printf("平衡二叉树建立成功!\n");
printf("请输入插入的结点:");
scanf("%d",&n);
InsertAVL(T,n,taller);
printf("插入成功!\n");
printf("请输入需要删除的结点:");
scanf("%d",&n);
DeleteAVL(T,n,shorter);
c=ASL(T);
printf("平均查找长度为:\n");
printf("ASL=%5.2f\n",c);
printf("其结果为:\n");
PrintBST(T);
printf("\n");
DestroyBST(T);
}


平衡二叉树及其操作实现