严蔚敏《数据结构c语言版习题集》答案第六章树和二叉树文库.docx
《严蔚敏《数据结构c语言版习题集》答案第六章树和二叉树文库.docx》由会员分享,可在线阅读,更多相关《严蔚敏《数据结构c语言版习题集》答案第六章树和二叉树文库.docx(33页珍藏版)》请在冰豆网上搜索。
严蔚敏《数据结构c语言版习题集》答案第六章树和二叉树文库
第六章树和二叉树
6.33
intIs_Descendant_C(intu,intv)//在孩子存储结构上判断u是否v的子孙,是则返回1,否则返回0
{
if(u==v)return1;
else
{
if(L[v])
if(Is_Descendant(u,L[v]))return1;
if(R[v])
if(Is_Descendant(u,R[v]))return1;//这是个递归算法
}
return0;
}//Is_Descendant_C
6.34
intIs_Descendant_P(intu,intv)//在双亲存储结构上判断u是否v的子孙,是则返回1,否则返回0
{
for(p=u;p!
=v&&p;p=T[p]);
if(p==v)return1;
elsereturn0;
}//Is_Descendant_P
6.35
这一题根本不需要写什么算法,见书后注释:
两个整数的值是相等的.
6.36
intBitree_Sim(BitreeB1,BitreeB2)//判断两棵树是否相似的递归算法
{
if(!
B1&&!
B2)return1;
elseif(B1&&B2&&Bitree_Sim(B1->lchild,B2->lchild)&&Bitree_Sim(B1->rchild,B2->rchild))
return1;
elsereturn0;
}//Bitree_Sim
6.37
voidPreOrder_Nonrecursive(BitreeT)//先序遍历二叉树的非递归算法
{
InitStack(S);
Push(S,T);//根指针进栈
while(!
StackEmpty(S))
{
while(Gettop(S,p)&&p)
{
visit(p->data);
push(S,p->lchild);
}//向左走到尽头
pop(S,p);
if(!
StackEmpty(S))
{
pop(S,p);
push(S,p->rchild);//向右一步
}
}//while
}//PreOrder_Nonrecursive
6.38
typedefstruct{
BTNode*ptr;
enum{0,1,2}mark;
}PMType;//有mark域的结点指针类型
voidPostOrder_Stack(BiTreeT)//后续遍历二叉树的非递归算法,用栈
{
PMTypea;
InitStack(S);//S的元素为PMType类型
Push(S,{T,0});//根结点入栈
while(!
StackEmpty(S))
{
Pop(S,a);
switch(a.mark)
{
case0:
Push(S,{a.ptr,1});//修改mark域
if(a.ptr->lchild)Push(S,{a.ptr->lchild,0});//访问左子树
break;
case1:
Push(S,{a.ptr,2});//修改mark域
if(a.ptr->rchild)Push(S,{a.ptr->rchild,0});//访问右子树
break;
case2:
visit(a.ptr);//访问结点,返回
}
}//while
}//PostOrder_Stack
分析:
为了区分两次过栈的不同处理方式,在堆栈中增加一个mark域,mark=0表示刚刚访问此结点,mark=1表示左子树处理结束返回,mark=2表示右子树处理结束返回.每次根据栈顶元素的mark域值决定做何种动作.
6.39
typedefstruct{
intdata;
EBTNode*lchild;
EBTNode*rchild;
EBTNode*parent;
enum{0,1,2}mark;
}EBTNode,EBitree;//有mark域和双亲指针域的二叉树结点类型
voidPostOrder_Nonrecursive(EBitreeT)//后序遍历二叉树的非递归算法,不用栈
{
p=T;
while(p)
switch(p->mark)
{
case0:
p->mark=1;
if(p->lchild)p=p->lchild;//访问左子树
break;
case1:
p->mark=2;
if(p->rchild)p=p->rchild;//访问右子树
break;
case2:
visit(p);
p->mark=0;//恢复mark值
p=p->parent;//返回双亲结点
}
}//PostOrder_Nonrecursive
分析:
本题思路与上一题完全相同,只不过结点的mark值是储存在结点中的,而不是暂存在堆栈中,所以访问完毕后要将mark域恢复为0,以备下一次遍历.
6.40
typedefstruct{
intdata;
PBTNode*lchild;
PBTNode*rchild;
PBTNode*parent;
}PBTNode,PBitree;//有双亲指针域的二叉树结点类型
voidInorder_Nonrecursive(PBitreeT)//不设栈非递归遍历有双亲指针的二叉树
{
p=T;
while(p->lchild)p=p->lchild;//向左走到尽头
while(p)
{
visit(p);
if(p->rchild)//寻找中序后继:
当有右子树时
{
p=p->rchild;
while(p->lchild)p=p->lchild;//后继就是在右子树中向左走到尽头
}
elseif(p->parent->lchild==p)p=p->parent;//当自己是双亲的左孩子时后继就是双亲
else
{
p=p->parent;
while(p->parent&&p->parent->rchild==p)p=p->parent;
p=p->parent;
}//当自己是双亲的右孩子时后继就是向上返回直到遇到自己是在其左子树中的祖先
}//while
}//Inorder_Nonrecursive
6.41
intc,k;//这里把k和计数器c作为全局变量处理
voidGet_PreSeq(BitreeT)//求先序序列为k的结点的值
{
if(T)
{
c++;//每访问一个子树的根都会使前序序号计数器加1
if(c==k)
{
printf("Valueis%d\n",T->data);
exit
(1);
}
else
{
Get_PreSeq(T->lchild);//在左子树中查找
Get_PreSeq(T->rchild);//在右子树中查找
}
}//if
}//Get_PreSeq
main()
{
...
scanf("%d",&k);
c=0;//在主函数中调用前,要给计数器赋初值0
Get_PreSeq(T,k);
...
}//main
6.42
intLeafCount_BiTree(BitreeT)//求二叉树中叶子结点的数目
{
if(!
T)return0;//空树没有叶子
elseif(!
T->lchild&&!
T->rchild)return1;//叶子结点
elsereturnLeaf_Count(T->lchild)+Leaf_Count(T->rchild);//左子树的叶子数加上右子树的叶子数
}//LeafCount_BiTree
6.43
voidBitree_Revolute(BitreeT)//交换所有结点的左右子树
{
T->lchild<->T->rchild;//交换左右子树
if(T->lchild)Bitree_Revolute(T->lchild);
if(T->rchild)Bitree_Revolute(T->rchild);//左右子树再分别交换各自的左右子树
}//Bitree_Revolute
6.44
intGet_Sub_Depth(BitreeT,intx)//求二叉树中以值为x的结点为根的子树深度
{
if(T->data==x)
{
printf("%d\n",Get_Depth(T));//找到了值为x的结点,求其深度
exit1;
}
else
{
if(T->lchild)Get_Sub_Depth(T->lchild,x);
if(T->rchild)Get_Sub_Depth(T->rchild,x);//在左右子树中继续寻找
}
}//Get_Sub_Depth
intGet_Depth(BitreeT)//求子树深度的递归算法
{
if(!
T)return0;
else
{
m=Get_Depth(T->lchild);
n=Get_Depth(T->rchild);
return(m>n?
m:
n)+1;
}
}//Get_Depth
6.45
voidDel_Sub_x(BitreeT,intx)//删除所有以元素x为根的子树
{
if(T->data==x)Del_Sub(T);//删除该子树
else
{
if(T->lchild)Del_Sub_x(T->lchild,x);
if(T->rchild)Del_Sub_x(T->rchild,x);//在左右子树中继续查找
}//else
}//Del_Sub_x
voidDel_Sub(BitreeT)//删除子树T
{
if(T->lchild)Del_Sub(T->lchild);
if(T->rchild)Del_Sub(T->rchild);
free(T);
}//Del_Sub
6.46
voidBitree_Copy_Nonrecursive(BitreeT,Bitree&U)//非递归复制二叉树
{
InitStack(S1);InitStack(S2);
push(S1,T);//根指针进栈
U=(BTNode*)malloc(sizeof(BTNode));
U->data=T->data;
q=U;push(S2,U);
while(!
StackEmpty(S))
{
while(Gettop(S1,p)&&p)
{
q->lchild=(BTNode*)malloc(sizeof(BTNode));
q=q->lchild;q->data=p->data;
push(S1,p->lchild);
push(S2,q);
}//向左走到尽头
pop(S1,p);
pop(S2,q);
if(!
StackEmpty(S1))
{
pop(S1,p);pop(S2,q);
q->rchild=(BTNode*)malloc(sizeof(BTNode));
q=q->rchild;q->data=p->data;
push(S1,p->rchild);//向右一步
push(S2,q);
}
}//while
}//BiTree_Copy_Nonrecursive
分析:
本题的算法系从6.37改写而来.
6.47
voidLayerOrder(BitreeT)//层序遍历二叉树
{
InitQueue(Q);//建立工作队列
EnQueue(Q,T);
while(!
QueueEmpty(Q))
{
DeQueue(Q,p);
visit(p);
if(p->lchild)EnQueue(Q,p->lchild);
if(p->rchild)EnQueue(Q,p->rchild);
}
}//LayerOrder
6.48
intfound=FALSE;
Bitree*Find_Near_Ancient(BitreeT,Bitreep,Bitreeq)//求二叉树T中结点p和q的最近共同祖先
{
Bitreepathp[100],pathq[100]//设立两个辅助数组暂存从根到p,q的路径
Findpath(T,p,pathp,0);
found=FALSE;
Findpath(T,q,pathq,0);//求从根到p,q的路径放在pathp和pathq中
for(i=0;pathp[i]==pathq[i]&&pathp[i];i++);//查找两条路径上最后一个相同结点
returnpathp[--i];
}//Find_Near_Ancient
voidFindpath(BitreeT,Bitreep,Bitreepath[],inti)//求从T到p路径的递归算法
{
if(T==p)
{
found=TRUE;
return;//找到
}
path[i]=T;//当前结点存入路径
if(T->lchild)Findpath(T->lchild,p,path,i+1);//在左子树中继续寻找
if(T->rchild&&!
found)Findpath(T->rchild,p,path,i+1);//在右子树中继续寻找
if(!
found)path[i]=NULL;//回溯
}//Findpath
6.49
intIsFull_Bitree(BitreeT)//判断二叉树是否完全二叉树,是则返回1,否则返回0
{
InitQueue(Q);
flag=0;
EnQueue(Q,T);//建立工作队列
while(!
QueueEmpty(Q))
{
DeQueue(Q,p);
if(!
p)flag=1;
elseif(flag)return0;
else
{
EnQueue(Q,p->lchild);
EnQueue(Q,p->rchild);//不管孩子是否为空,都入队列
}
}//while
return1;
}//IsFull_Bitree
分析:
该问题可以通过层序遍历的方法来解决.与6.47相比,作了一个修改,不管当前结点是否有左右孩子,都入队列.这样当树为完全二叉树时,遍历时得到是一个连续的不包含空指针的序列.反之,则序列中会含有空指针.
6.50
StatusCreateBitree_Triplet(Bitree&T)//输入三元组建立二叉树
{
if(getchar()!
='^')returnERROR;
T=(BTNode*)malloc(sizeof(BTNode));
p=T;p->data=getchar();
getchar();//滤去多余字符
InitQueue(Q);
EnQueue(Q,T);
while((parent=getchar())!
='^'&&(child=getchar())&&(side=getchar()))
{
while(QueueHead(Q)!
=parent&&!
QueueEmpty(Q))DeQueue(Q,e);
if(QueueEmpty(Q))returnERROR;//未按层序输入
p=QueueHead(Q);
q=(BTNode*)malloc(sizeof(BTNode));
if(side=='L')p->lchild=q;
elseif(side=='R')p->rchild=q;
elsereturnERROR;//格式不正确
q->data=child;
EnQueue(Q,q);
}
returnOK;
}//CreateBitree_Triplet
6.51
StatusPrint_Expression(BitreeT)//按标准形式输出以二叉树存储的表达式
{
if(T->data是字母)printf("%c",T->data);
elseif(T->data是操作符)
{
if(!
T->lchild||!
T->rchild)returnERROR;//格式错误
if(T->lchild->data是操作符&&T->lchild->data优先级低于T->data)
{
printf("(");
if(!
Print_Expression(T->lchild))returnERROR;
printf(")");
}//注意在什么情况下要加括号
elseif(!
Print_Expression(T->lchild))returnERROR;
if(T->rchild->data是操作符&&T->rchild->data优先级低于T->data)
{
printf("(");
if(!
Print_Expression(T->rchild))returnERROR;
printf(")");
}
elseif(!
Print_Expression(T->rchild))returnERROR;
}
elsereturnERROR;//非法字符
returnOK;
}//Print_Expression
6.52
typedefstruct{
BTNodenode;
intlayer;
}BTNRecord;//包含结点所在层次的记录类型
intFanMao(BitreeT)//求一棵二叉树的"繁茂度"
{
intcountd;//count数组存放每一层的结点数
InitQueue(Q);//Q的元素为BTNRecord类型
EnQueue(Q,{T,0});
while(!
QueueEmpty(Q))
{
DeQueue(Q,r);
count[r.layer]++;
if(r.node->lchild)EnQueue(Q,{r.node->lchild,r.layer+1});
if(r.node->rchild)EnQueue(Q,{r.node->rchild,r.layer+1});
}//利用层序遍历来统计各层的结点数
h=r.layer;//最后一个队列元素所在层就是树的高度
for(maxn=count[0],i=1;count[i];i++)
if(count[i]>maxn)maxn=count[i];//求层最大结点数
returnh*maxn;
}//FanMao
分析:
如果不允许使用辅助数组,就必须在遍历的同时求出层最大结点数,形式上会复杂一些,你能写出来吗?
6.53
intmaxh;
StatusPrintpath_MaxdepthS1(BitreeT)//求深度等于树高度减一的最靠左的结点
{
Bitreepathd;
maxh=Get_Depth(T);//Get_Depth函数见6.44
if(maxh<2)returnERROR;//无符合条件结点
Find_h(T,1);
returnOK;
}//Printpath_MaxdepthS1
voidFind_h(BitreeT,inth)//寻找深度为maxh-1的结点
{
path[h]=T;
if(h==maxh-1)
{
for(i=1;path[i];i++)printf("%c",path[i]->data);
exit;//打印输出路径
}
else
{
if(T->lchild)Find_h(T->lchild,h+1);
if(T->rchild)Find_h(T->rchild,h+1);
}
path[h]=NULL;//回溯
}//Find_h
6.54
StatusCreateBitree_SqList(Bitree&T,SqListsa)//根据顺序存储结构建立二叉链表
{
Bitreeptr[sa.last+1];//该数组储存与sa中各结点对应的树指针
if(!
sa.last)
{
T=NULL;//空树
return;
}
ptr[1]=(BTNode*)malloc(sizeof(BTNode));
ptr[1]->data=sa.elem[1];//建立树根
T=ptr[1];
for(i=2;i<=sa.last;i++)
{
if(!
sa.elem[i])returnERROR;//顺序错误
ptr[i]=(BTNode*)malloc(sizeof(BTNode));
ptr[i]->data=sa.elem[i];
j=i/2;//找到结点i的双亲j
if(i-j*2)ptr[j]->rchild=ptr[i];//i是j的右孩子
elseptr[j]->lchild=ptr[i];//i是j的左孩子
}
returnOK;
}//CreateBitree_SqList
6.55
intDescNum(BitreeT)//求树结点T的子孙总数填入DescNum域中,并返回该数
{
if(!
T)return-1;
elsed=(DescNum(T->lchild)+DescNum(T->rchild)+2);//计算公式
T->DescNum=d;
returnd;
}//DescNum
分析:
该算法时间复杂度为O(n),n为树结点总数.注意:
为了能用一个统一的公式计算子孙数目,所以当T为空指针时,要返回-1而不是0.
6.56
BTNode*PreOrder_Next(BTNode*p)//在先序后继线索二叉树中查找结点p的先序后继,并返回指针
{
if(p->lchild)returnp->lchild;
elsereturnp->rchild;
}//PreOrder_Next
分析:
总觉得不会这么简单.是不是哪儿理解错了?
6.57
BitreePostOrder_Next(Bitreep)//在后序后继线索二叉树中查找结点p的后序后继,并返回指针
{
if(p->rtag)returnp->rchild;//p有后继线索