数据结构C语言版第五六章习题答案Word文档格式.docx
《数据结构C语言版第五六章习题答案Word文档格式.docx》由会员分享,可在线阅读,更多相关《数据结构C语言版第五六章习题答案Word文档格式.docx(21页珍藏版)》请在冰豆网上搜索。
![数据结构C语言版第五六章习题答案Word文档格式.docx](https://file1.bdocx.com/fileroot1/2023-1/14/ba1c68c7-55c4-41ae-b743-4d41bf95aa7e/ba1c68c7-55c4-41ae-b743-4d41bf95aa7e1.gif)
中序序列与后序序列相同
先序序列与中序序列相同
中序序列与层次遍历序列相同
先序遍历二叉树的顺序是“根—左子树—右子树”,中序遍历“左子树—根—右子树”,后序遍历顺序是:
“左子树—右子树―根",根据以上原则,本题解答如下:
(1)
若先序序列与后序序列相同,则或为空树,或为只有根结点的二叉树
(2)
若中序序列与后序序列相同,则或为空树,或为任一结点至多只有左子树的二叉树.
(3)
若先序序列与中序序列相同,则或为空树,或为任一结点至多只有右子树的二叉树.
(4)
若中序序列与层次遍历序列相同,则或为空树,或为任一结点至多只有右子树的二叉树
(2)设一棵二叉树的先序序列:
ABDFCEGH,中序序列:
BFDAGEHC
画出这棵二叉树。
画出这棵二叉树的后序线索树。
将这棵二叉树转换成对应的树(或森林)。
(1)
(2)
(3)假设用于通信的电文仅由8个字母组成,字母在电文中出现的频率分别为0.07,0.19,0.02,0.06,0.32,0.03,0.21,0.10。
试为这8个字母设计赫夫曼编码。
试设计另一种由二进制表示的等长编码方案。
对于上述实例,比较两种方案的优缺点。
解:
方案1;
哈夫曼编码
先将概率放大100倍,以方便构造哈夫曼树。
w={7,19,2,6,32,3,21,10},按哈夫曼规则:
【[(2,3),6],(7,10)】,……19,21,32
(100)
(40)(60)
192132(28)
(17)(11)
7106(5)
23
方案比较:
方案1的WPL=2(0.19+0.32+0.21)+4(0.07+0.06+0.10)+5(0.02+0.03)=1.44+0.92+0.25=2.61
方案2的WPL=3(0.19+0.32+0.21+0.07+0.06+0.10+0.02+0.03)=3
结论:
哈夫曼编码优于等长二进制编码
(4)已知下列字符A、B、C、D、E、F、G的权值分别为3、12、7、4、2、8,11,试填写出其对应哈夫曼树HT的存储结构的初态和终态。
初态:
weight
parent
lchild
rchild
1
3
2
12
7
4
5
6
8
11
9
10
13
15
20
27
47
终态
3.算法设计题
以二叉链表作为二叉树的存储结构,编写以下算法:
(1)统计二叉树的叶结点个数。
intLeafNodeCount(BiTreeT)
{
if(T==NULL)
return0;
//如果是空树,则叶子结点个数为0
elseif(T->
lchild==NULL&
&
T->
rchild==NULL)
return1;
//判断该结点是否是叶子结点(左孩子右孩子都为空),若是则返回1
else
returnLeafNodeCount(T->
lchild)+LeafNodeCount(T->
rchild);
}
(2)判别两棵树是否相等。
(3)交换二叉树每个结点的左孩子和右孩子。
voidChangeLR(BiTree&
T)
BiTreetemp;
if(T->
return;
{
temp=T->
lchild;
T->
lchild=T->
rchild;
rchild=temp;
}
ChangeLR(T->
lchild);
(4)设计二叉树的双序遍历算法(双序遍历是指对于二叉树的每一个结点来说,先访问这个结点,再按双序遍历它的左子树,然后再一次访问这个结点,接下来按双序遍历它的右子树)。
voidDoubleTraverse(BiTreeT)
if(T==NULL)
cout<
<
data;
DoubleTraverse(T->
(5)计算二叉树最大的宽度(二叉树的最大宽度是指二叉树所有层中结点个数的最大值)。
[题目分析]求二叉树高度的算法见上题。
求最大宽度可采用层次遍历的方法,记下各层结点数,每层遍历完毕,若结点数大于原先最大宽度,则修改最大宽度。
intWidth(BiTreebt)//求二叉树bt的最大宽度
{if(bt==null)return(0);
//空二叉树宽度为0
else
{BiTreeQ[];
//Q是队列,元素为二叉树结点指针,容量足够大
front=1;
rear=1;
last=1;
//front队头指针,rear队尾指针,last同层最右结点在队列中的位置
temp=0;
maxw=0;
//temp记局部宽度,maxw记最大宽度
Q[rear]=bt;
//根结点入队列
while(front<
=last)
{p=Q[front++];
temp++;
//同层元素数加1
if(p->
lchild!
=null)Q[++rear]=p->
//左子女入队
if(p->
rchild!
//右子女入队
if(front>
last)//一层结束,
{last=rear;
if(temp>
maxw)maxw=temp;
//last指向下层最右元素,更新当前最大宽度
}//if
}//while
return(maxw);
}//结束width
(6)用按层次顺序遍历二叉树的方法,统计树中具有度为1的结点数目。
intLevel(BiTreebt)//层次遍历二叉树,并统计度为1的结点的个数
{intnum=0;
//num统计度为1的结点的个数
if(bt){QueueInit(Q);
QueueIn(Q,bt);
//Q是以二叉树结点指针为元素的队列
while(!
QueueEmpty(Q))
{p=QueueOut(Q);
printf(p->
data);
//出队,访问结点
if(p->
lchild&
!
p->
rchild||!
p->
rchild)num++;
//度为1的结点
lchild)QueueIn(Q,p->
//非空左子女入队
rchild)QueueIn(Q,p->
//非空右子女入队
}}//if(bt)
return(num);
}//返回度为1的结点的个数
(7)求任意二叉树中第一条最长的路径长度,并输出此路径上各结点的值。
[题目分析]因为后序遍历栈中保留当前结点的祖先的信息,用一变量保存栈的最高栈顶指针,每当退栈时,栈顶指针高于保存最高栈顶指针的值时,则将该栈倒入辅助栈中,辅助栈始终保存最长路径长度上的结点,直至后序遍历完毕,则辅助栈中内容即为所求。
voidLongestPath(BiTreebt)//求二叉树中的第一条最长路径长度
{BiTreep=bt,l[],s[];
//l,s是栈,元素是二叉树结点指针,l中保留当前最长路径中的结点
inti,top=0,tag[],longest=0;
while(p||top>
0)
{while(p){s[++top]=p;
tag[top]=0;
p=p->
Lc;
}//沿左分枝向下
if(tag[top]==1)//当前结点的右分枝已遍历
{if(!
s[top]->
Lc&
Rc)//只有到叶子结点时,才查看路径长度
if(top>
longest){for(i=1;
i<
=top;
i++)l[i]=s[i];
longest=top;
top--;
//保留当前最长路径到l栈,记住最高栈顶指针,退栈
elseif(top>
0){tag[top]=1;
p=s[top].Rc;
}//沿右子分枝向下
}//while(p!
=null||top>
}//结束LongestPath
(8)输出二叉树中从每个叶子结点到根结点的路径。
[题目分析]采用先序遍历的递归方法,当找到叶子结点*b时,由于*b叶子结点尚未添加到path中,因此在输出路径时还需输出b->
data值。
对应的递归算法如下:
voidAllPath(BTNode*b,ElemTypepath[],intpathlen)
inti;
if(b!
=NULL)
if(b->
lchild==NULL&
b->
rchild==NULL)//*b为叶子结点
cout<
"
<
data<
到根结点路径:
"
for(i=pathlen-1;
i>
=0;
i--)
endl;
path[pathlen]=b->
//将当前结点放入路径中
pathlen++;
//路径长度增1
AllPath(b->
lchild,path,pathlen);
//递归扫描左子树
rchild,path,pathlen);
//递归扫描右子树
pathlen--;
//恢复环境
第6章图
(1)在一个图中,所有顶点的度数之和等于图的边数的()倍。
A.1/2B.1C.2D.4
(2)在一个有向图中,所有顶点的入度之和等于所有顶点的出度之和的()倍。
A.1/2B.1C.2D.4
(3)具有n个顶点的有向图最多有()条边。
A.nB.n(n-1)C.n(n+1)D.n2
(4)n个顶点的连通图用邻接距阵表示时,该距阵至少有()个非零元素。
A.nB.2(n-1)C.n/2D.n2
(5)G是一个非连通无向图,共有28条边,则该图至少有()个顶点。
A.7B.8C.9D.10
(6)若从无向图的任意一个顶点出发进行一次深度优先搜索可以访问图中所有的顶点,则该图一定是()图。
A.非连通B.连通C.强连通D.有向
(7)下面( )算法适合构造一个稠密图G的最小生成树。
A.Prim算法B.Kruskal算法C.Floyd算法D.Dijkstra算法
(8)用邻接表表示图进行广度优先遍历时,通常借助()来实现算法。
A.栈B.队列C.树D.图
(9)用邻接表表示图进行深度优先遍历时,通常借助()来实现算法。
A.栈B.队列C.树D.图
(10)深度优先遍历类似于二叉树的()。
A.先序遍历B.中序遍历C.后序遍历D.层次遍历
(11)广度优先遍历类似于二叉树的()。
A.先序遍历B.中序遍历C.后序遍历D.层次遍历
(12)图的BFS生成树的树高比DFS生成树的树高()。
A.小B.相等C.小或相等D.大或相等
A.0243156
B.0136542
C.0134256
D.0361542
(13)已知图的邻接矩阵如图6.25所示,则从顶点0出发按深度优先遍历的结果是()。
图6.25邻接矩阵
(14)已知图的邻接表如图6.26所示,则从顶点0出发按广度优先遍历的结果是(),按深度优先遍历的结果是()。
A.0132B.0231
C.0321D.0123
图6.26邻接表
(15)下面()方法可以判断出一个有向图是否有环。
A.深度优先遍历B.拓扑排序C.求最短路径D.求关键路径
(1)已知如图6.27所示的有向图,请给出:
每个顶点的入度和出度;
邻接矩阵;
邻接表;
逆邻接表。
图6.27有向图
(2)已知如图6.28所示的无向网,请给出:
最小生成树
图6.28无向网
a
→
b
c
d
e
^
h
f
g
4^
(3)已知图的邻接矩阵如6.29所示。
试分别画出自顶点1出发进行遍历所得的深度优先生成树和广度优先生成树。
图6.29邻接矩阵
(4)有向网如图6.30所示,试用迪杰斯特拉算法求出从顶点a到其他各顶点间的最短路径,完成表6.9。
图6.30有向网
D
终点
i=1
i=2
i=3
i=4
i=5
i=6
(a,b)
(a,c)
(a,d)
(a,c,f,d)
∞
(a,c,e)
(a,c,f)
16
(a,c,f,g)
14
(a,c,f,d,g)
S
终点集
{a,c}
{a,c,f}
{a,c,f,e}
{a,c,f,e,d}
{a,c,f,e,d,g}
{a,c,f,e,d,g,b}
(5)试对图6.31所示的AOE-网:
求这个工程最早可能在什么时间结束;
求每个活动的最早开始时间和最迟开始时间;
图6.31AOE-网
确定哪些活动是关键活动
【解答】按拓扑有序的顺序计算各个顶点的最早可能开始时间Ve和最迟允许开始时间Vl。
然后再计算各个活动的最早可能开始时间e和最迟允许开始时间l,根据l-e=0?
来确定关键活动,从而确定关键路径。
1
2
3
4
5
6
Ve
0
19
15
29
38
43
Vl
37
38
1,2>
1,3>
3,2>
2,4>
2,5>
3,5>
4,6>
5,6>
e
l
17
27
l-e
8
12
此工程最早完成时间为43。
关键路径为<
(1)分别以邻接矩阵和邻接表作为存储结构,实现以下图的基本操作:
增添一个新顶点v,InsertVex(G,v);
删除顶点v及其相关的边,DeleteVex(G,v);
增加一条边<
v,w>
,InsertArc(G,v,w);
删除一条边<
,DeleteArc(G,v,w)。
//本题中的图G均为有向无权图,其余情况容易由此写出
StatusInsert_Vex(MGraph&
G,charv)//在邻接矩阵表示的图G上插入顶点v
if(G.vexnum+1)>
MAX_VERTEX_NUMreturnINFEASIBLE;
G.vexs[++G.vexnum]=v;
returnOK;
}//Insert_Vex
StatusInsert_Arc(MGraph&
G,charv,charw)//在邻接矩阵表示的图G上插入边(v,w)
if((i=LocateVex(G,v))<
0)returnERROR;
if((j=LocateVex(G,w))<
if(i==j)returnERROR;
if(!
G.arcs[j].adj)
G.arcs[j].adj=1;
G.arcnum++;
}//Insert_Arc
StatusDelete_Vex(MGraph&
G,charv)//在邻接矩阵表示的图G上删除顶点v
n=G.vexnum;
if((m=LocateVex(G,v))<
G.vexs[m]<
->
G.vexs[n];
//将待删除顶点交换到最后一个顶点
for(i=0;
n;
i++)
G.arcs[m]=G.arcs[n];
//将边的关系随之交换
G.arcs[m][m].adj=0;
G.vexnum--;
}//Delete_Vex
分析:
如果不把待删除顶点交换到最后一个顶点的话,算法将会比较复杂,而伴随着大量元素的移动,时间复杂度也会大大增加.
StatusDelete_Arc(MGraph&
G,charv,charw)//在邻接矩阵表示的图G上删除边(v,w)
if(G.arcs[j].adj)
G.arcs[j].adj=0;
G.arcnum--;
}/