树与二叉树答案说明.docx
- 文档编号:25678465
- 上传时间:2023-06-11
- 格式:DOCX
- 页数:21
- 大小:83.37KB
树与二叉树答案说明.docx
《树与二叉树答案说明.docx》由会员分享,可在线阅读,更多相关《树与二叉树答案说明.docx(21页珍藏版)》请在冰豆网上搜索。
树与二叉树答案说明
此程序功能比课程设计要求的要多,可作为复习资料,测试用原始二叉树如左图,共有两次运行结果截图,每次所删除的子树不同,务必自行分析各步结果得到的过程.注意最初输入时含有的空格数(abc空d空空空ef空空g空h空空),附录中含有源码,务必认真阅读!
//头文件包含
#include
#include
#include
//函数状态码定义
#defineTRUE1
#defineFALSE0
#defineOK1
#defineERROR0
#defineOVERFLOW-1
#defineINFEASIBLE-2
#defineNULL0
typedefintStatus;
//以下为二叉树的类型定义及创建、销毁、遍历、求树深、求结点数、叶结点数、复制、左右互换、查找、定位双亲、删除、凹式输出等操作实现--------
//树中元素类型定义与二叉链表存储结构定义
typedefcharTElemType;
typedefstructBiTNode{
TElemTypedata;
structBiTNode*lchild,*rchild;
}BiTNode,*BiTree;
StatusCreateBiTree(BiTree&T){//先序创建二叉树各结点,注意输入时空指针不要丢
TElemTypee;
scanf("%c",&e);
if(e=='')T=NULL;
else{
T=(BiTree)malloc(sizeof(BiTNode));
if(!
T)exit(OVERFLOW);
T->data=e;
CreateBiTree(T->lchild);
CreateBiTree(T->rchild);
}
returnOK;
}
StatusDestroyBiTree(BiTree&T)//销毁以T为根结点的树,注意T各子孙结点也要释放
{
if(T){
DestroyBiTree(T->lchild);
DestroyBiTree(T->rchild);
free(T);
T=NULL;
}
returnOK;
}
intTreeDepth(BiTreeT){
intd,d1,d2;
if(T==NULL)d=0;
else
{
d1=TreeDepth(T->lchild);
d2=TreeDepth(T->rchild);
d=d1>=d2?
d1+1:
d2+1;
}
returnd;
}
intNodeCount(BiTreeT){
//递归法统计所有结点的个数
intn;
if(T==NULL)n=0;
elsen=1+NodeCount(T->lchild)+NodeCount(T->rchild);
returnn;
}
intLeafCount(BiTreeT){
//递归法统计叶子结点的个数
intn;
if(T==NULL)n=0;
elseif(T->lchild==NULL&&T->rchild==NULL)n=1;
elsen=LeafCount(T->lchild)+LeafCount(T->rchild);
returnn;
}
StatusPrintTElem(TElemTypee){
printf("%c",e);
returnOK;
}
StatusPreOrderTraverse(BiTreeT,Status(*visit)(TElemType))
{
if(T){
(*visit)(T->data);
PreOrderTraverse(T->lchild,(*visit));
PreOrderTraverse(T->rchild,(*visit));
}
returnOK;
}
StatusInOrderTraverse(BiTreeT,Status(*visit)(TElemType))
{
if(T){
InOrderTraverse(T->lchild,(*visit));
(*visit)(T->data);
InOrderTraverse(T->rchild,(*visit));
}
returnOK;
}
StatusPostOrderTraverse(BiTreeT,Status(*visit)(TElemType))
{
if(T){
PostOrderTraverse(T->lchild,(*visit));
PostOrderTraverse(T->rchild,(*visit));
(*visit)(T->data);
}
returnOK;
}
intPreOrder_LeafCount(BiTreeT,int&count){
//基于先序遍历求叶结点数,count用作计数器,初值为。
函数返回值为叶结点数。
实际将先序遍历过程中的visit函数变为判断当前结点是否为叶子节点、是则加的操作即可
if(!
T)returncount;
else{
if(!
T->lchild&&!
T->rchild)++count;
PreOrder_LeafCount(T->lchild,count);
PreOrder_LeafCount(T->rchild,count);
returncount;
}
}
StatusCopyBiTree(BiTreeT,BiTree&X){//复制树T得到树X,T保持不变
if(!
T)X=NULL;
else{
X=(BiTree)malloc(sizeof(BiTNode));
if(!
X)exit(OVERFLOW);
X->data=T->data;
CopyBiTree(T->lchild,X->lchild);
CopyBiTree(T->rchild,X->rchild);
}
returnOK;
}
StatusExchangeBiTree(BiTree&T){//将树T各结点的左右孩子互换
BiTreetemp;
if(T){
temp=T->lchild;
T->lchild=T->rchild;
T->rchild=temp;
ExchangeBiTree(T->lchild);
ExchangeBiTree(T->rchild);
}
returnOK;
}
StatusLocateNode(BiTreeT,TElemTypex,BiTree&p){
//在树T中查找(按先序)第一个结点值等于x的结点,若找到则函数返回TRUE,p带回该结点的地址;若找不到则函数返回FALSE ,p赋值为NULL
if(!
T){p=NULL;returnFALSE;}//树T为空则p赋空且返回FALSE
elseif(T->data==x){p=T;returnTRUE;}
else{
if(LocateNode(T->lchild,x,p))returnTRUE;//搜索左子树
elseif(LocateNode(T->rchild,x,p))returnTRUE;//左子树中找不到再搜索右子树
else{p=NULL;returnFALSE;}
}
}
StatusLocateParent(BiTreeT,TElemTypex,BiTree&parent_p,int&LR){
//已知树T中存在某结点值等于x,定位到该结点的双亲结点,若双亲存在(说明x结点非根结点)则parent_p带回双亲位置,flag为代表是双亲的左孩子,为代表是双亲的右孩子,同时函数返回TRUE;否则函数返回FALSE
if(T->data==x){parent_p=NULL;returnFALSE;}//值等于x的结点是根结点,无双亲
else{
if(T->lchild!
=NULL&&T->lchild->data==x){parent_p=T;LR=0;returnTRUE;}
elseif(T->rchild!
=NULL&&T->rchild->data==x){parent_p=T;LR=1;returnTRUE;}
else{
if(T->lchild!
=NULL&&LocateParent(T->lchild,x,parent_p,LR))returnTRUE;
elseif(T->rchild!
=NULL&&LocateParent(T->rchild,x,parent_p,LR))returnTRUE;
else{parent_p=NULL;returnFALSE;}
}
}
}
StatusDeleteChild(BiTree&T,TElemTypex){
//删除树T中以x为根结点的子树,若存在x结点则删除成功后返回OK,若不存在x结点返回ERROR;
BiTNode*p,*parent_p;
intLR;
if(LocateNode(T,x,p)){//若树中存在结点x
if(LocateParent(T,x,parent_p,LR)){//若存在双亲,即x非根结点
if(LR==0)DestroyBiTree(parent_p->lchild);
elseif(LR==1)DestroyBiTree(parent_p->rchild);
}
elseDestroyBiTree(T);//若x为根结点,不存在双亲,则删除整颗树,不可直接写T=NULL,为何?
returnOK;
}
else
returnERROR;
}
//-------------------以下为孩子兄弟表示法存储的树或森林的类型定义及树的相关操作实现-------------------------------------
typedefstructCSNode{
TElemTypedata;
structCSNode*firstchild;
structCSNode*nextsibling;
}CSNode,*CSTree;
StatusBiTreetoTreeorForest(BiTreeBiT,CSTree&T){
//根据已经存在的二叉树BiT转换得到孩子兄弟法表示的树或者森林T,原二叉树BiT保持不变。
注意思考何时得到树,何时得到森林
if(BiT==NULL)T=NULL;
else{
T=(CSTree)malloc(sizeof(CSNode));
if(!
T)exit(OVERFLOW);
T->data=BiT->data;
BiTreetoTreeorForest(BiT->lchild,T->firstchild);
BiTreetoTreeorForest(BiT->rchild,T->nextsibling);
}
returnOK;
}
StatusPostRootTraverse(CSTreeT,Status(*visit)(TElemType)){
//后根序遍历树T(对森林则是中序遍历),相当于中序遍历二叉链表存储结构
if(T){
PostRootTraverse(T->firstchild,(*visit));
(*visit)(T->data);
PostRootTraverse(T->nextsibling,(*visit));
}
returnOK;
}
intTreeorForestDepth(CSTreeT){//求树或森林的深度
intd,d1,d2;
if(!
T)d=0;
else{
d1=TreeorForestDepth(T->firstchild);
d2=TreeorForestDepth(T->nextsibling);
d=(d1+1)>d2?
d1+1:
d2;
}
returnd;
}
voidPrintBiTree(BiTreeT,intlevel){
//仿照题集题凹式打印树的形式打印二叉树
//注意是逐行打印,采用先序,凹入深度由结点所在层次控制,根结点位于第层,故最初level为
if(T){
//先根据当前结点所处层次打印若干空格以缩进,每层所尽量为(level-1)*4个空格
for(inti=1;i<=level-1;++i)printf("");
printf("%c\n",T->data);
PrintBiTree(T->lchild,level+1);
PrintBiTree(T->rchild,level+1);
}
}
voidPrintTree(CSTreeT,intlevel){
//按题集题凹式打印树
//注意是逐行打印,采用先根序,凹入深度由结点所在层次控制,根结点位于第层,故最初level为
if(T){
//先根据当前结点所处层次打印若干空格以缩进,每层所尽量为(level-1)*4个空格
for(inti=1;i<=level-1;++i)printf("");
printf("%c\n",T->data);
PrintTree(T->firstchild,level+1);
PrintTree(T->nextsibling,level);
}
}
//以下非课程设计要求部分,可作复习用//
//------非递归实现树的遍历时需用到栈,故此处将顺序栈的定义及实现复制过来,不过栈元素类型需改变为指向树的结点的指针类型BiTree---
//元素类型与顺序栈类型声明
#defineSTACK_INIT_SIZE100
#defineSTACKINCREMENT10
typedefBiTreeElemType;//BiTree等同于BiTNode*,说明栈中的元素类型为指向树中结点的指针类型
typedefstruct{
ElemType*base;
ElemType*top;
intstacksize;
}SqStack;
//顺序栈基本操作及其实现
StatusInitStack(SqStack&S){
//初始化一个顺序栈用S带回
S.base=(ElemType*)malloc(STACK_INIT_SIZE*sizeof(ElemType));
if(!
S.base)returnERROR;
S.top=S.base;
S.stacksize=STACK_INIT_SIZE;
returnOK;
}
StatusDestroyStack(SqStack&S){
//销毁一个顺序栈
free(S.base);
S.base=NULL;
S.top=NULL;
S.stacksize=0;
returnOK;
}
StatusClearStack(SqStack&S){
//将一个顺序栈置空
S.top=S.base;
returnOK;
}
StatusPush(SqStack&S,ElemTypee){
//向栈顶压入一个新元素
if((S.top-S.base)==S.stacksize){//当前栈满则重新为栈分配空间
S.base=(ElemType*)realloc(S.base,(S.stacksize+STACKINCREMENT)*sizeof(ElemType));
if(!
S.base)returnERROR;
S.top=S.base+S.stacksize;
S.stacksize+=STACKINCREMENT;
}
*S.top++=e;
returnOK;
}
StatusPop(SqStack&S,ElemType&e){
//栈顶元素出栈并用e带回其值
if(S.top==S.base)returnERROR;
e=*(S.top-1);
--S.top;
returnOK;
}
StatusSetTopElem(SqStack&S,ElemTypee){
//将栈顶元素的值修改为e,书中未设此操作,可根据需要新设
if(S.top==S.base)returnERROR;
*(S.top-1)=e;
returnOK;
}
StatusStackEmpty(SqStackS){
//栈空则返回TRUE,否则返回FALSE
if(S.top==S.base)returnTRUE;
elsereturnFALSE;
}
intStackLength(SqStackS){
//返回栈中元素的个数
return(S.top-S.base);
}
StatusGetTop(SqStackS,ElemType&e){
//用e带回栈顶元素的值
if(S.top==S.base)returnERROR;
e=*(S.top-1);
returnOK;
}
StatusPrintElem(ElemTypee){
//用于输出一个元素,根据元素类型的不同,此函数需适时改变
printf("%c",e->data);
returnOK;
}
StatusStackTraverse(SqStackS,Status(*visit)(ElemType)){
//从栈底元素到栈顶元素依次执行visit函数,通常用于输出栈中元素
ElemType*p=S.base;
if(S.base==S.top)printf("空栈\n");
else
while(p returnOK; } StatusInOrderTraverse_NonRecur_1(BiTreeT,Status(*visit)(ElemType)){ //本问题共两种求解思路,此为第一种 //何时递归: 根结点不空时递归访问左子树(因还要回来访问根结点,故根结点入栈,左孩子成为新根结点) //何时不递归: 左子树空时栈顶根结点出栈访问,并将右孩子入栈 //结束: 当前访问结点为空且栈中无元素时遍历毕 SqStackS;InitStack(S);BiTNode*p=T; while(p||! StackEmpty(S)){ while(p){ Push(S,p); p=p->lchild; } Pop(S,p); (*visit)(p); p=p->rchild; } returnOK; } StatusInOrderTraverse_NonRecur_2(BiTreeT,Status(*visit)(ElemType)){ //非递归中序遍历二叉树T //何时递归: 根结点不空时将左孩子入栈作新根结点, //何时不递归: 根结点为空时不递归,此后当前空根结点出栈,访问下一个栈顶元素并将其右孩子结点入栈 //当栈中不含元素时整个树遍历完毕 SqStackS; InitStack(S); BiTNode*p;//实际BiTree与BiTNode*等价,具体根据上下文含义确定用谁,如根结点可声明为BiTree类型,指向结点的指针可声明为BiTNode*类型 if(! T){printf("空树");returnERROR;} else{ Push(S,T); while(! StackEmpty(S)){ while(GetTop(S,p)&&p)Push(S,p->lchild);//p的左孩子入栈,直到入栈元素为空指针,此循环后栈顶元素为NULL,相当于走到左子树外 Pop(S,p);//左子树是空树,对应的空指针出栈,下一步将访问根结点 if(! StackEmpty(S)){//若栈中尚有元素代表未遍历完,下面访问栈顶根结点,之后栈顶跟结点的右孩子入栈 Pop(S,p); (*visit)(p); Push(S,p->rchild); } } returnOK; } } voidmain() { BiTreeBiT; CreateBiTree(BiT); printf("二叉树BiT的先序输出序列为: "); PreOrderTraverse(BiT,PrintTElem); printf("\n"); printf("二叉树BiT的中序输出为: "); InOrderTraverse(BiT,PrintTElem); printf("\n"); printf("二叉树BiT后序输出为: "); PostOrderTraverse(BiT,PrintTElem); printf("\n\n"); printf("二叉树BiT树深: %d\n",TreeDepth(BiT)); printf("二叉树BiT结点总数: %d\n",NodeCount(BiT)); printf("递归求得二叉树BiT叶子结点数为: %d\n",LeafCount(BiT)); intcount=0; printf("基于先序遍历求二叉树BiT叶子结点数为: %d\n\n",PreOrder_LeafCount(BiT,count)); TElemTypex; BiTreep,parent_p;//BiTree等价于BiTNode* intLR; printf("输入要查找的元素,元素值前加一个空格: ");//此处在%c前加一个空格,因在主函数第一个输入语句执行时用户最后会输入一个回车,此处不加空格则x变为回车,不会再等待输入.若结点元素为整型则无此问题 scanf("%c",&x);//此处在%c前加一个空格,因在主函数第一个输入语句执行时用户最后会输入一个回车,此处不加空格则x变为回车,不会再等待输入.若结点元素为整型则无此问题 if(LocateNode(BiT,x,p)==TRUE){ printf("元素%c在BiT中,",p->data); if(LocateParent(BiT,x,parent_p,LR)){ printf("%c结点的双亲结点为%c,",x,parent_p->data); if(LR==0)printf("是双亲的左孩子\n"); els
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 二叉 答案 说明