实验报告平衡二叉树.docx
- 文档编号:25366785
- 上传时间:2023-06-07
- 格式:DOCX
- 页数:31
- 大小:171KB
实验报告平衡二叉树.docx
《实验报告平衡二叉树.docx》由会员分享,可在线阅读,更多相关《实验报告平衡二叉树.docx(31页珍藏版)》请在冰豆网上搜索。
实验报告平衡二叉树
实习报告
、需求分析
1、问题描述
利用平衡二叉树实现一个动态查找表。
(1)实现动态查找表的三种基本功能:
查找、插入和删除。
(2)初始时,平衡二叉树为空树,操作界面给出查找、插入和删除三种操作供选择。
每种操作均要提示输入关键字。
在查找时,如果查找的关键字不存在,则把其插入到平衡二叉树中。
每次插入或删除一个结点后,应更新平衡二叉树的显示。
(3)每次操作的关键字都要从文件中读取,并且关键字的集合限定为短
整型数字{1,2,3},关键字出现的顺序没有限制,允许出现重复的
关键字,并对其进行相应的提示。
(4)平衡二叉树的显示采用图形界面画出图形。
2、系统功能
打开数据文件,用文件中的关键字来演示平衡二叉树操作的过程。
〃在平衡的二叉树中插入关键字;//在平衡的二叉树中查找关键字;//显示调整过的平衡二叉树;
//删除平衡二叉树中的关键字;
//结束。
4、测试数据:
平衡二叉树为:
图1插入关键字10之前的平衡二叉树
插入关键字:
10;调整后:
图2插入关键字10之后的平衡二叉树
删除关键字:
14;调整后:
查找关键字:
11;
输出:
Thedataishere!
图3查找关键字11后的平衡二叉树
二、概要设计
本次实验目的是为了实现动态查找表的三种基本功能:
查找、插入和删除。
动态查找表可有不同的表示方法,在此次实验中主要是以平衡二叉树的结构来表示实现的,所以需要两个抽象数据类型:
动态查找表和二叉树。
1、动态查找表的抽象数据类型定义为:
ADTDynamicSearchTable
{数据对象D:
D是具有相同特性的数据元素的集合。
各个数据元素均含有类型相同,可唯一标识数据元素的关键字。
数据关系R:
数据元素同属于一个集合。
基本操作P:
InitDSTable(&ST);
操作结果:
构造一个空的动态查找表DT。
'、DestroyDSTable(&DT);
\初始条件:
动态查找表DT存在。
\操作结果:
销毁动态查找表DT。
SearchDSTable(DT,key);
初始条件:
动态查找表DT存在,key为和关键字类型相同的给丁值。
操作结果:
若DT中存在其关键字等于key的数据元素,则函数值为\该元素的值或在表中的位置,否则为“空”。
/
InsertDSTable(&DT,e);
初始条件:
动态查找表DT存在,e为待插入的数据元素。
操作结果:
若DT中不存在其关键字等于e,key的数据元素,则插入e至UDT;/
DeleteDSTable(&DT,key);
初始条件:
动态查找表DT存在,key为和关键字类型相同的给定值。
操作结果:
若DT中存在其关键字等于key的数据元素,则删除之。
}ADTDynamicSearchTable
2、二叉树抽象数据类型的定义为:
ADTBinaryTree
{数据对象D:
D是具有相同特性的数据元素的集合。
数据关系R:
若D=g,贝UR=称BinaryTree为空的二叉树;
若D工0,贝UR={H},H是如下二元关系:
(1)在D中存在唯一的称为根的数据元素root,它在关系H下无前
驱;/、
(2)若D—{root}工0,则存在D—{root}={D1,Dr},且D1nDr=C;
(3)若D1工0,贝UD1中存在唯一的元素x1,
/素xr,
(4)(D1,{H1})是一棵符合本定义的二叉树,称为根的左子树,
(Dr,{Hr})是符合本定义的二叉树,称为根的右子树。
基本操作P:
InitBiTree(&T);
操作结果:
构造空的二叉树T;
DestroyBiTree(&T);
初始条件:
二叉树T存在。
操作结果:
销毁二叉树T。
CreateBiTree(&T,definition);
初始条件:
definition给出T的定义。
操作结果:
按definition构造二叉树T。
BiTreeEmpty(T);
初始条件:
二叉树T存在。
操作结果:
若T为空二叉树,则返回TRUE,否则FALSE。
LeftChild(T,e);
初始条件:
二叉树T存在,e是T中某个结点。
操作结果:
返回e的左孩子。
若e无左孩子,则返回“空”。
RightChild(T,e);
初始条件:
二叉树T存在,e是T中某个结点。
操作结果:
返回e的右孩子。
若e无右孩子,则返回“空”。
InsertAVL(T,e,taller);
初始条件:
二叉树T存在,e为要插入的结点,taller反映T长高与否。
操作结果:
若在平衡二叉树中不存在和e相同关键字的结点,则插入一个数据元素为e的结点,并返回1,否则返回0。
若因插入而使二叉排序树失去平衡,则旋转处理。
RightProcess(T);
初始条件:
二叉树T存在。
操作结果:
对以T为根的二叉树做右旋转处理,处理之后T指向新的树根结点。
LeftProcess(T);
初始条件:
二叉树T存在。
操作结果:
对以T为根的二叉树做左旋转处理,处理之后T指向新的树根结点
}
3、本程序包括四个模块:
(1)主程序模块:
voidmain()
{for(;;)
{switch()
{
接受命令;
/处理命令;
/}
/}
/}
(2)二叉树单元模块:
实现二叉树的抽象数据类型。
(3)动态查找表单元模块:
实现动态查找表的抽象数据类型。
(4)结点结构模块:
实现平衡二叉树的查找、插入和删除操作。
各模块之间的关系:
图4各模块之间的关系
三、详细设计
1、元素类型、结点类型和指针类型;
typedefintInfoType
typedefstructnode/*记录类型*/
{
InfoTypedata;
Structnodelchild,rchild;
/*其他数据域*/
/*左右孩子指针*/
}BSTNode,*BSTree;
statusMakeNode(BSTNode&p,ElemTypee)
{/*分配由p指向的数据元素为e、后继为"空"的结点,并返回TRUE,扩若
分配失败,则返回FALSE*/'\
p=(BSTNode*)malloc(sizeof(BSTNode);
if(!
p)returnFALSE;
p->data=e;
p->next=NULL;\
returnTRUE;
}
voidFreeNode(BSTNode&p)
{/*释放p所指结点*/
}
2、根据动态查找表的基本操作特点:
表结构本身是在查找过程中动态产生的,即对于给定值key,若表中存在其关键字等于key的记录,则查找成功返回,否则插入关键字等于key的记录。
在此次试验中主要是利用平衡二叉树来实现动态查找表。
平衡二叉排序树定义为:
typedefintInfoTypetypedefintKeyType;
/*元素类型*/
typedefstructnode
{
KeyTypekey;intbf;
InfoTypedata;
Structnodelchild,rchild;
/*关键字项*/
/*平衡因子*/
/*其他数据域*/
/*左右孩子指针*/
}BSTNode,*BSTree;
inttaller;/*taller=O,平衡二叉数没有长高不需要调整;taller=1,二叉数长高,
需要验证是否还是平衡二叉数,如果不是,则需要进行调整.*/
平衡二叉树的基本操作定义如下:
intInsertAVL(BSTNode*b,KeyTypee,int*m);
//如果在平衡二叉排序树b中不存在e有相同关键字的结点,则插入一个数据元素为e的新结点,并返回1,否则返回0•如果因插入而使二叉排序树失去平衡,则做平衡处理,指针m反应b长高与否。
voidLeftProcess(BSTree*p,int*m);
//在插入结点时对以指针p所指结点为根的二叉树做左平衡旋转处理。
voidRightProcess(BSTree*p,int*m);
//在插入结点时对以指针p所指结点为根的二叉树做右平衡旋转处理。
intDeleteAVL(BSTree*p,KeyTypex,int*m);/
〃在以p为根的平衡二叉树中删除关键字为e的结点,如果因删除而使平衡
二叉树失去平衡,则做平衡处理,指针m反应b树长高与否。
voidLeftProcess1(BSTree*p,int*m);
//由DeleteAVL()函数调用,在删除结点时进行左处理。
voidRightProcess1(BSTree*p,int*m);
//由DeleteAVL()函数调用,在删除结点时进行右处理。
voidDelete2(BSTreeq,BSTree*r,int*m);
//由DeleteAVL()调用,用于处理被删除结点都不为空的情况。
voidDrawTree(BSTreeb);
〃对以b为根的平衡二叉树,以括号的形式显示出来。
voidOutputTree(BSTreeb,intfx,intfy,intprex,intprey);
〃用图形把平衡二叉树显示出来。
3、本程序实现的是演示平衡二叉树的操作过程,包括插入和删除操作,以下是它们算法的设计。
(1)插入数据操作,如果数据存在,输出提示信息,如果不存在,则把此数据插入到入平衡二叉树中,并做相应的调整,使之还为平衡二叉树。
以下是对插入操作的设计。
intInsertAVL(BSTree*b,KeyTypee,int*m)
/*若在平衡的二叉排序树中b中不存在和e有相同关键字的结点,则插入一个数据元素为e的新结点,并返回0。
若因插入而使二叉排序树失去平衡,则做平衡旋转处理,taller的值反应长高与否。
*/
{if(*b==NULL)
/*原为空树,插入新结点,树长高,置taller=*m=1*/
{(*b)=(BSTNode*)malloc(sizeof(BSTNode));
(*b)->key=e;
(*b)->lchild=(*b)->rchild=NULL;
(*b)->bf=0;
*m=1;
}
else
{if(e==(*b)->key)
/*树中已存在和e有相同关键字的结点,则不再进行插入*/
{*m=0;
/*置taller=*m=0,树没有长高,不须进行调整*/
printf("\nThedataishere!
\n");/*输出提示信息*/return0;
}
if(e<(*b)->key)
/*继续在*b的左子树中进行搜索*/
{if((InsertAVL(&((*b)->lchild),e,&taller))==0)
return0;
if(taller==1)
/*存在和e有相同关键字的元素,则不需要插入*/
/*已插入在*b的左子树中且左子树长咼*/
LeftProcess(&(*b),&taller);
}
else/*已插入在*b的右子树中且左子树长高*/
{if((lnsertAVL(&((*b)->rchild),e,&taller))==O)
return0;/*存在和e有相同关键字的元素则不需要插入*/
if(taller==1)/*已插入在*b的右子树中且右子树长高*/
RightProcess(&(*b),&taller);
}
}
return1;
}
voidLeftProcess(BSTree*p,int*m)
/*对以指针p所指结点为根的二叉树做左平衡旋转处理,算法结束后,指针p指向新的根结点*/
{BSTNode*p1,*p2;
if((*p)->bf==0)/*原本左右子树等高,现因左子树增高而使树增高*/
{(*p)->bf=1;
*m=1;
}
elseif((*p)->bf==-1)/*原本右子树比左子树高,现左右子树等高*/
{(*p)->bf=0;
*m=0;
}else
{p1=(*p)->lchild;
if(p1->bf==1)
/*树没有长高*/
{(*p)->lchild=p1->rchild;p1->rchild=(*p);
(*p)->bf=p1->bf=0;
*p=p1;
/*原本左子树比右子树高,需做左子树的平衡处理*/
/*p1指向*p的左子树根结点*/
/*新结点插入在*p的左孩子的右子树上,要做LL调整*/
/*p的左孩子为p1的右孩子*/
/*p1的右孩子为p*/
/*p和p1的平衡因子都变为0*/
/*p1取代以前p的位置*/
}
elseif(p1->bf==-1)
{p2=p1->rchild;p1->rchild=p2->lchild;p2->lchild=p1;(*p)->lchild=p2->rchild;p2->rchild=*p;
if(p2->bf==0)(*p)->bf=p1->bf=0;elseif(p2->bf==1){p1->bf=0;
(*p)->bf=-1;
}
/*新结点插在p2的左子树上的情况*/
/*如果新结点插在*b的左子树根结点的右子树上,需做
LR调整*/
/*p2指向p1的右子树根结点*//*p1的右孩子为p2的左孩子*/
/*p2的左孩子为p1*/
/*p的左孩子为p2的右孩子*/
/*p2的右孩子为p*/
/*新结点插在p2处做叶子结点的情况*/
else/*新结点插在p2的右子树上的情况*/
{p1->bf=1;
(*p)->bf=O;
}
*p=p2;
(*p)->bf=O;/*仍将p指向新的根结点,并置其平衡因子为0*/
}
*m=0;/*返回值为*m=taller,在InsertAVL()递归调用时,依次判
/断每个结点的平衡因子是否在(-1,1)之间*/
}
}
voidRightProcess(BSTree*p,int*m)
/*对以指针p所指结点为根的二叉树做左平衡旋转处理,算法结束后,指针p指向新的根结点*/
{BSTNode*p1,*p2;
if((*p)->bf==0)/*原本左右子树等高,现因右子树增高而使树增高*/
{(*p)->bf=-1;
/*原本右子树比左子树高,需做右子树的平衡处理*/
/*p1指向*p的右子树根结点*/
/*如果新结点插在*b的左子树根结点的右子树上,需做
RR调整*/
{(*p)->rchild=p1->lchild;
p1->lchild=*p;
(*p)->bf=p1->bf=0;
*p=p1;
}
elseif(p1->bf==1)/*新结点插入在*p的右孩子的左子树上,要做RL调整
*/
{p2=p1->lchild;
p1->lchild=p2->rchild;
p2->rchild=p1;
(*p)->rchild=p2->lchild;
p2->lchild=*p;
if(p2->bf==0)/*新结点插在p2处做叶子结点的情况*/
(*p)->bf=p1->bf=0;
elseif(p2->bf==-1)/*新结点插在p2的右子树上的情况*/
{p1->bf=0;
(*p)->bf=1;
}
else/*新结点插在p2的左子树上的情况*/
{p1->bf=-1;
(*p)->bf=0;
}
*p=p2;
(*p)->bf=0;/*仍将p指向新的根结点,并置其平衡因子为0*/
}
*m=0;
}
}
(2)以下是对删除算法的设计和实现。
假设要删除关键字为x的结点,如果x
不在叶子结点上,则用它左子数中的最大值或最小值取代x;如此反复取代,
直到删除动作传递到某个叶子接点。
删除叶子结点时,若需要进行平衡变换,可采用插入的平衡变换的反变换(如:
左子树变矮对应于右子树长高);
intDeleteAVL(BSTree*p,KeyTypex,int*m)
{/*在AVL树中删除关键字为x的结点。
*/
intk;
BSTNode*q;
if((*p)==NULL)
return0;
elseif(x<(*p)->key)
{k=DeleteAVL(&((*p)->lchild),x,&taller);
if(taller==1)
LeftProcess1(&(*p),&taller);
returnk;
}
elseif(x>(*p)->key)
{k=DeleteAVL(&((*p)->rchild),x,&taller);
if(taller==1)
RightProcess1(&(*p),&taller);
returnk;
}
else/*找到了关键字为x的结点,由p指向它。
*/
{q=(*p);
if((*p)->rchild==NULL)/*被删结点右子树为空。
*/
{(*p)=(*p)->lchild;
free(q);
*m=1;
}
elseif((*p)->lchild==NULL)/*被删结点左子树为空。
*/
{*p=(*p)->rchild;
free(q);
*m=1;
}
else/*被删结点左右子树都不为空。
*/
{Delete2(q,&(q->lchild),&taller);
if(taller==1)
LeftProcess1(&q,&taller);
(*p)=q;
}
return1;
}
}voidLeftProcess1(BSTree*p,int*m)
/*在删除结点时进行左处理。
*/
{BSTNode*p1,*p2;
if((*p)->bf==1)
{(*p)->bf=0;/*需做RR调整。
*/
*m=1;
}
elseif((*p)->bf==0)
{(*p)->bf=-1;
*m=0;
\}
else
{p仁(*p)->rchild;
if(p1->bf==O)
{(*p)->rchild=p1->lchild;
p1->lchild=*p;
p1->bf=1;(*p)->bf=-1;
*p=p1;
*m=0;
}\
elseif(p1->bf==-1)/*需做RR调整。
*/
{(*p)->rchild=p1->lchild;
p1->lchild=*p;
(*p)->bf=p1->bf=0;
*p=p1;
*m=1;
else/*需做RL调整。
*/
{p2=p1->lchild;
p1->lchild=p2->rchild;p2->rchild=p1;
(*p)->rchild=p2->lchild;
p2->lchild=*p;
if(p2->bf==0){(*p)->bf=O;
p1->bf=0;
/}
elseif(p2->bf==-1){(*p)->bf=1;
p1->bf=0;
}
else
{(*p)->bf=O;
p1->bf=-1;
}
p2->bf=0;
*p=p2;
*m=1;
}
}
}
voidRightProcess1(BSTree*p,int*m)
/*在删除结点时进行右处理。
*/
{BSTNode*p1,*p2;
if((*p)->bf==-1)
{(*p)->bf=0;
*m=-1;
\}
elseif((*p)->bf==0)
{(*p)->bf=1;
*m=0;
}
else
{p1=(*p)->lchild;
if(p1->bf==0)/*需做LL调整。
*/
{(*p)->lchild=p1->rchild;
p1->rchild=*p;
p1->bf=-1;(*p)->bf=1;
*p=p1;
*m=0;
}
elseif(p1->bf==1)/*需做LL调整。
*/
{(*p)->lchild=p1->rchild;p1->rchild=*p;(*p)->bf=p1->bf=0;(*p)=p1;*m=1;
}
else
{p2=p1->rchild;
p1->rchild=p2->lchild;
p2->lchild=p1;
(*p)->lchild=p2->rchild;\
p2->rchild=*p;
if(p2->bf==0)
{(*p)->bf=0;
p1->bf=0;
}
elseif(p2->bf==1)
{(*p)->bf=-1;
p1->bf=0;
}
else/*需做LR调整。
*/
{(*p)->bf=0;
p1->bf=1;
}
p2->bf=0;
*p=p2;
*m=1;
}
}
}
voidDelete2(BSTreeq,BSTree*r,int*m)
/*由DeleteAVL()调用,用于处理被删除结点左右子树均不为空的情况。
*/
{if((*r)->rchild==NULL)
{q->key=(*r)->key;
q=*r;
*r=(*r)->lchild;
free(q);
*m=1;
}
else
{Delete2(q,&((*r)->rchild),&taller);
if(taller==1)
RightProcess1(&(*r),&taller);
}
}
(3)以下是对二叉树输出的设计,包括以括号的形式输出和以图形的形式输出
voidDispBSTree(BSTreeb)
/*以括号的形式输出*/
{
if(b!
=NULL)
{printf("%d",b->key);
if(b->lchild!
=NULL||b->rchild!
=NULL)
{printf("(");
DispBSTree(b->lchild);
if(b->rchild!
=NULL)
printf(",");
DispBSTree(b->rchild);
printf(")");
}
}
}
voidOutputTree(BSTreeb,intfx,intfy,intprex,intprey)
/*以图形的形式输出*/
{charstr[30];
if(b)
{
b->x=fx;
b->y=fy;
sprintf(str,"%d",b->key);
setcolor(RED);
outtextxy(fx-2,fy-2,str);
setcolor(
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 实验 报告 平衡 二叉