第六章 树和二叉树文档格式.docx
《第六章 树和二叉树文档格式.docx》由会员分享,可在线阅读,更多相关《第六章 树和二叉树文档格式.docx(19页珍藏版)》请在冰豆网上搜索。
}//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);
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;
//S的元素为PMType类型
Push(S,{T,0});
//根结点入栈
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});
rchild)Push(S,{a.ptr->
rchild,0});
//访问右子树
case2:
visit(a.ptr);
//访问结点,返回
}//PostOrder_Stack
分析:
为了区分两次过栈的不同处理方式,在堆栈中增加一个mark域,mark=0表示刚刚访问此结点,mark=1表示左子树处理结束返回,mark=2表示右子树处理结束返回.每次根据栈顶元素的mark域值决定做何种动作.
6.39
intdata;
EBTNode*lchild;
EBTNode*rchild;
EBTNode*parent;
}EBTNode,EBitree;
//有mark域和双亲指针域的二叉树结点类型
voidPostOrder_Nonrecursive(EBitreeT)//后序遍历二叉树的非递归算法,不用栈
p=T;
while(p)
switch(p->
mark)
p->
mark=1;
if(p->
lchild)p=p->
lchild;
mark=2;
rchild)p=p->
rchild;
visit(p);
mark=0;
//恢复mark值
p=p->
parent;
//返回双亲结点
}//PostOrder_Nonrecursive
本题思路与上一题完全相同,只不过结点的mark值是储存在结点中的,而不是暂存在堆栈中,所以访问完毕后要将mark域恢复为0,以备下一次遍历.
6.40
PBTNode*lchild;
PBTNode*rchild;
PBTNode*parent;
}PBTNode,PBitree;
//有双亲指针域的二叉树结点类型
voidInorder_Nonrecursive(PBitreeT)//不设栈非递归遍历有双亲指针的二叉树
while(p->
//向左走到尽头
rchild)//寻找中序后继:
当有右子树时
//后继就是在右子树中向左走到尽头
elseif(p->
parent->
lchild==p)p=p->
//当自己是双亲的左孩子时后继就是双亲
parent&
rchild==p)p=p->
}//当自己是双亲的右孩子时后继就是向上返回直到遇到自己是在其左子树中的祖先
}//Inorder_Nonrecursive
6.41
intc,k;
//这里把k和计数器c作为全局变量处理
voidGet_PreSeq(BitreeT)//求先序序列为k的结点的值
if(T)
c++;
//每访问一个子树的根都会使前序序号计数器加1
if(c==k)
printf("
Valueis%d\n"
T->
exit
(1);
Get_PreSeq(T->
//在左子树中查找
//在右子树中查找
}//if
}//Get_PreSeq
main()
...
scanf("
%d"
&
k);
c=0;
//在主函数中调用前,要给计数器赋初值0
Get_PreSeq(T,k);
}//main
6.42
intLeafCount_BiTree(BitreeT)//求二叉树中叶子结点的数目
T)return0;
//空树没有叶子
elseif(!
T->
lchild&
rchild)return1;
//叶子结点
elsereturnLeaf_Count(T->
lchild)+Leaf_Count(T->
//左子树的叶子数加上右子树的叶子数
}//LeafCount_BiTree
6.43
voidBitree_Revolute(BitreeT)//交换所有结点的左右子树
lchild<
->
//交换左右子树
if(T->
lchild)Bitree_Revolute(T->
rchild)Bitree_Revolute(T->
//左右子树再分别交换各自的左右子树
}//Bitree_Revolute
6.44
intGet_Sub_Depth(BitreeT,intx)//求二叉树中以值为x的结点为根的子树深度
data==x)
%d\n"
Get_Depth(T));
//找到了值为x的结点,求其深度
exit1;
lchild)Get_Sub_Depth(T->
lchild,x);
rchild)Get_Sub_Depth(T->
rchild,x);
//在左右子树中继续寻找
}//Get_Sub_Depth
intGet_Depth(BitreeT)//求子树深度的递归算法
m=Get_Depth(T->
n=Get_Depth(T->
return(m>
n?
m:
n)+1;
}//Get_Depth
6.45
voidDel_Sub_x(BitreeT,intx)//删除所有以元素x为根的子树
data==x)Del_Sub(T);
//删除该子树
lchild)Del_Sub_x(T->
rchild)Del_Sub_x(T->
//在左右子树中继续查找
}//else
}//Del_Sub_x
voidDel_Sub(BitreeT)//删除子树T
lchild)Del_Sub(T->
rchild)Del_Sub(T->
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(Gettop(S1,p)&
q->
lchild=(BTNode*)malloc(sizeof(BTNode));
q=q->
data=p->
push(S1,p->
push(S2,q);
pop(S1,p);
pop(S2,q);
StackEmpty(S1))
pop(S1,p);
q->
rchild=(BTNode*)malloc(sizeof(BTNode));
q=q->
push(S1,p->
push(S2,q);
}//BiTree_Copy_Nonrecursive
本题的算法系从6.37改写而来.
6.47
voidLayerOrder(BitreeT)//层序遍历二叉树
InitQueue(Q);
//建立工作队列
EnQueue(Q,T);
QueueEmpty(Q))
DeQueue(Q,p);
lchild)EnQueue(Q,p->
rchild)EnQueue(Q,p->
}//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;
//当前结点存入路径
lchild)Findpath(T->
lchild,p,path,i+1);
//在左子树中继续寻找
rchild&
found)Findpath(T->
rchild,p,path,i+1);
//在右子树中继续寻找
found)path[i]=NULL;
//回溯
}//Findpath
6.49
intIsFull_Bitree(BitreeT)//判断二叉树是否完全二叉树,是则返回1,否则返回0
flag=0;
p)flag=1;
elseif(flag)return0;
EnQueue(Q,p->
//不管孩子是否为空,都入队列
}//IsFull_Bitree
该问题可以通过层序遍历的方法来解决.与6.47相比,作了一个修改,不管当前结点是否有左右孩子,都入队列.这样当树为完全二叉树时,遍历时得到是一个连续的不包含空指针的序列.反之,则序列中会含有空指针.
6.50
StatusCreateBitree_Triplet(Bitree&
T)//输入三元组建立二叉树
if(getchar()!
='
^'
)returnERROR;
T=(BTNode*)malloc(sizeof(BTNode));
data=getchar();
getchar();
//滤去多余字符
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'
rchild=q;
elsereturnERROR;
//格式不正确
data=child;
EnQueue(Q,q);
returnOK;
}//CreateBitree_Triplet
6.51
StatusPrint_Expression(BitreeT)//按标准形式输出以二叉树存储的表达式
data是字母)printf("
%c"
elseif(T->
data是操作符)
lchild||!
rchild)returnERROR;
//格式错误
lchild->
data是操作符&
data优先级低于T->
data)
("
);
Print_Expression(T->
lchild))returnERROR;
)"
}//注意在什么情况下要加括号
rchild->
rchild))returnERROR;
//非法字符
}//Print_Expression
6.52
typedefstruct{
BTNodenode;
intlayer;
}BTNRecord;
//包含结点所在层次的记录类型
intFanMao(BitreeT)//求一棵二叉树的"
繁茂度"
intcountd;
//count数组存放每一层的结点数
//Q的元素为BTNRecord类型
EnQueue(Q,{T,0});
DeQueue(Q,r);
count[r.layer]++;
if(r.node->
lchild)EnQueue(Q,{r.node->
lchild,r.layer+1});
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);
}//Printpath_MaxdepthS1
voidFind_h(BitreeT,inth)//寻找深度为maxh-1的结点
path[h]=T;
if(h==maxh-1)
for(i=1;
path[i];
i++)printf("
path[i]->
exit;
//打印输出路径
lchild)Find_h(T->
lchild,h+1);
rchild)Find_h(T->
rchild,h+1);
path[h]=NULL;
}//Find_h
6.54
StatusCreateBitree_SqList(Bitree&
T,SqListsa)//根据顺序存储结构建立二叉链表
Bitreeptr[sa.last+1];
//该数组储存与sa中各结点对应的树指针
sa.las