【问题描述】
查找表是数据处理的重要操作, 试建立有100个结点的二叉排序树进行查找,然后用原数据建立AVL树, 并比较两者的平均查找长度。
【基本要求】
(1)以链表作为存储结构,实现二叉排序树的建立、查找和删除。
(2)根据给定的数据建立平衡二叉树。
(3)比较二叉排序树和平衡二叉树的平均查找长度。
【测试数据】
随机生成。
【实现提示】
(1)初始,二叉排序树和平衡二叉树都为空树,操作界面给出查找、插入和删除三种操作供选择。每种操作均要提示输入关键字。每次插入或删除一个结点后,应更新平衡二叉树或二叉排序树的显示。
(2)平衡二叉树或二叉排序树的显示可以采用凹入表形式,也可以采用图形界面画出树形。
树的结构体类型定义:
struct node{
int data;//数据项
int degree;//平衡二叉树的平衡因子
node *lchild;
node *rchild;//左右孩子
node *parent;
int length;
};
这里定义了父母指针,主要用途在于删除结点时使用。还有查找长度。
首先说明生成二叉排序树的思路:
以插入为基础算法,不断地插入新的结点,从而构造一棵二叉排序树。
AVL树(平衡二叉树)的基本思路相同,但需要不断地做平衡处理。
二叉排序树的递归插入:
node *binary_sort_tree(node* &T,int a){
//产生普通二叉排序树,即插入操作
if(T== NULL){
T=new node;
T->data=a;
T->lchild=NULL;
T->rchild=NULL;
T->parent=NULL;
}
else if(a < T->data){
T->lchild=binary_sort_tree(T->lchild,a);
T->lchild->parent=T;
}
else if(a> T->data){
T->rchild=binary_sort_tree(T->rchild,a);
T->rchild->parent=T;
}
else
cout<<"该结点已存在,请勿重复插入"<<endl;
return T;
}
AVL树的难点在于平衡思路,可以分为两大类,四小类:
L型:因左子树插入结点而引起的失衡
LL型——>单次右旋转一次。
LR型——>首先左旋转左子树一次,再右旋转大树一次。
R型:因右子树插入结点而引起的失衡
RR型——>单次左旋转一次。
RL型——>首先右旋转右子树一次,再左旋转大树一次。
主要的插入函数负责两大类:L与R型的平衡。而其名下的两小类,则分别由LeftBalance与RightBalance函数处理平衡。
这里由最底层的函数开始给出:
单次左旋转函数:
void L_Rotate(node* &T){
//对树作左旋处理
node* rc=T->rchild;
T->rchild=rc->lchild;
rc->lchild=T;
T=rc;
}
单次右旋转函数:
void R_Rotate(node* &T){
//对树作右旋处理
node* lc=T->lchild;
T->lchild=lc->rchild;
lc->rchild=T;
T=lc;
}
左平衡函数:
void LeftBalance(node* &T){
node *lc=T->lchild;
switch(lc->degree){
case 1:
T->degree=0;
lc->degree=0;
R_Rotate(T);
break;
case -1:
node *rd=lc->rchild;
switch(rd->degree){
case 1:
T->degree=-1;
lc->degree=0;
break;
case 0:
T->degree=0;
lc->degree=0;
break;
case -1:
T->degree=0;
lc->degree=1;
break;
}
rd->degree=0;
L_Rotate(T->lchild);
R_Rotate(T);
}
}
右平衡函数:
void RightBalance(node* &T){
node *rc=T->rchild;
switch(rc->degree){
case -1:
T->degree=0;
rc->degree=0;
L_Rotate(T);
break;
case 1:
node *ld=rc->lchild;
switch(ld->degree){
case 1:
T->degree=0;
rc->degree=-1;
break;
case 0:
T->degree=0;
rc->degree=0;
break;
case -1:
T->degree=1;
rc->degree=0;
}
ld->degree=0;
R_Rotate(T->rchild);//单次右旋转右子树
L_Rotate(T);//单次左旋转树
}
}
最后是最关键的插入操作函数:
int InsertAVL(node* &T,int a,int &flag){
//构造平衡二叉树
if(!T){
T=new node;
T->data=a;
T->lchild=NULL;
T->rchild=NULL;
T->degree=0;//平衡因子
flag=1;//反映树长高与否
}
else{
int length;
if(search_tree(T,a,length)){
flag=0;
return 0;
}
if(T->data>a){
if(!InsertAVL(T->lchild,a,flag))
return 0;
if(flag)
switch(T->degree){
case 1:
LeftBalance(T);
flag=0;
break;
case 0:
T->degree=1;
flag=1;
break;
case -1:
T->degree=0;
flag=0;
break;
}
}
else{
if(!InsertAVL(T->rchild,a,flag))
return 0;
if(flag)
switch(T->degree