数据结构第6章二叉树自测题参考答案Word文件下载.docx
《数据结构第6章二叉树自测题参考答案Word文件下载.docx》由会员分享,可在线阅读,更多相关《数据结构第6章二叉树自测题参考答案Word文件下载.docx(18页珍藏版)》请在冰豆网上搜索。
7.二叉树的基本组成部分是:
根(N)、左子树(L)和右子树(R)。
因而二叉树的遍历次序有六种。
最常用的是三种:
前序法(即按NLR次序),后序法(即按LRN次序)和中序法(也称对称序法,即按LNR次序)。
这三种方法相互之间有关联。
若已知一棵二叉树的前序序列是BEFCGDH,中序序列是FEBGCHD,则它的后序序列必是FEGHDCB。
解:
法1:
先由已知条件画图,再后序遍历得到结果;
法2:
不画图也能快速得出后序序列,只要找到根的位置特征。
由前序先确定root,由中序先确定左子树。
例如,前序遍历BEFCGDH中,根结点在最前面,是B;
则后序遍历中B一定在最后面。
法3:
递归计算。
如B在前序序列中第一,中序中在中间(可知左右子树上有哪些元素),则在后序中必为最后。
如法对B的左右子树同样处理,则问题得解。
8.中序遍历的递归算法平均空间复杂度为O(n)。
即递归最大嵌套层数,即栈的占用单元数。
精确值应为树的深度k+1,包括叶子的空域也递归了一次。
9.用5个权值{3,2,4,5,1}构造的哈夫曼(Huffman)树的带权路径长度是33。
先构造哈夫曼树,得到各叶子的路径长度之后便可求出WPL=(4+5+3)×
2+(1+2)×
3=33
(15)
(9)(6)(注:
两个合并值先后不同会导致编码不同,即哈夫曼编码不唯一)
453(3)(注:
合并值应排在叶子值之后)
12
(注:
原题为选择题:
A.32B.33C.34D.15)
三、单项选择题(每小题1分,共11分)
(C)1.不含任何结点的空树。
(A)是一棵树;
(B)是一棵二叉树;
(C)是一棵树也是一棵二叉树;
(D)既不是树也不是二叉树
以前的标答是B,因为那时树的定义是n≥1
(C)2.二叉树是非线性数据结构,所以。
(A)它不能用顺序存储结构存储;
(B)它不能用链式存储结构存储;
(C)顺序存储结构和链式存储结构都能存储;
(D)顺序存储结构和链式存储结构都不能使用
(C)3.具有n(n>
0)个结点的完全二叉树的深度为。
(A)log2(n)(B)log2(n)(C)log2(n)+1(D)log2(n)+1
注1:
x表示不小于x的最小整数;
x表示不大于x的最大整数,它们与[]含义不同!
注2:
选(A)是错误的。
例如当n为2的整数幂时就会少算一层。
似乎log2(n)+1是对的?
(A)4.把一棵树转换为二叉树后,这棵二叉树的形态是。
(A)唯一的(B)有多种
(C)有多种,但根结点都没有左孩子(D)有多种,但根结点都没有右孩子
5.从供选择的答案中,选出应填入下面叙述?
内的最确切的解答,把相应编号写在答卷的对应栏内。
树是结点的有限集合,它A根结点,记为T。
其余的结点分成为m(m≥0)个B
的集合T1,T2,…,Tm,每个集合又都是树,此时结点T称为Ti的父结点,Ti称为T的子结点(1≤i≤m)。
一个结点的子结点个数为该结点的C。
供选择的答案
A:
①有0个或1个②有0个或多个③有且只有1个④有1个或1个以上
B:
①互不相交②允许相交③允许叶结点相交④允许树枝结点相交
C:
①权②维数③次数(或度)④序
答案:
ABC=1,1,3
6.从供选择的答案中,选出应填入下面叙述?
二叉树A。
在完全的二叉树中,若一个结点没有B,则它必定是叶结点。
每棵树都能惟一地转换成与它对应的二叉树。
由树转换成的二叉树里,一个结点N的左子女是N在原树里对应结点的C,而N的右子女是它在原树里对应结点的D。
①是特殊的树②不是树的特殊形式③是两棵树的总称④有是只有二个根结点的树形结构
①左子结点②右子结点③左子结点或者没有右子结点④兄弟
C~D:
①最左子结点②最右子结点③最邻近的右兄弟④最邻近的左兄弟
⑤最左的兄弟⑥最右的兄弟
A=B=C=D=
ABCDE=2,1,1,3
四、简答题(每小题4分,共20分)
C的结点类型定义如下:
structnode
{chardata;
structnode*lchild,rchild;
};
C算法如下:
voidtraversal(structnode*root)
{if(root)
{printf(“%c”,root->
data);
traversal(root->
lchild);
printf(“%c”,root->
traversal(root->
rchild);
}
1.设如下图所示的二叉树B的存储结构为二叉链表,root为根指针,结点结构为:
(lchild,data,rchild)。
其中lchild,rchild分别为指向左右孩子的指针,data为字符型,root为根指针,试回答下列问题:
1.对下列二叉树B,执行下列算法traversal(root),试指出其输出结果;
2.假定二叉树B共有n个结点,试分析算法traversal(root)的时间复杂度。
(共8分)
二叉树B
这是“先根再左再根再右”,比前序遍历多打印各结点一次,输出结果为:
ABCCEEBADFFDGG
特点:
①每个结点肯定都会被打印两次;
②但出现的顺序不同,其规律是:
凡是有左子树的结点,必间隔左子树的全部结点后再重复出现;
如A,B,D等结点。
反之马上就会重复出现。
如C,E,F,G等结点。
时间复杂度以访问结点的次数为主,精确值为2*n,时间渐近度为O(n).
2.给定二叉树的两种遍历序列,分别是:
前序遍历序列:
D,A,C,E,B,H,F,G,I;
中序遍历序列:
D,C,B,E,H,A,G,I,F,
试画出二叉树B,并简述由任意二叉树B的前序遍历序列和中序遍历序列求二叉树B的思想方法。
方法是:
由前序先确定root,由中序可确定root的左、右子树。
然后由其左子树的元素集合和右子树的集合对应前序遍历序列中的元素集合,可继续确定root的左右孩子。
将他们分别作为新的root,不断递归,则所有元素都将被唯一确定,问题得解。
D
A
CF
EG
BHI
3.略
五、阅读分析题(每题5分,共20分)
1.试写出如图所示的二叉树分别按先序、中序、后序遍历时得到的结点序列。
DLR:
ABDFJGKCEHILM
LDR:
BFJDGKACHELIM
LRD:
JFKGDBHLMIECA
2.把如图所示的树转化成二叉树。
注意全部兄弟之间都要连线(包括度为2的兄弟),并注意原有连线结点一律归入左子树,新添连线结点一律归入右子树。
A
B
EC
KFHD
LGI
MJ
这是找结点后继的程序。
共有3处错误。
当rtag=1时说明内装后继指针,可直接返回,第一句无错。
当rtag=0时说明内装右孩子指针,但孩子未必是后继,需要计算。
中序遍历应当先左再根再右,所以应当找左子树直到叶子处。
r=r->
lchild;
直到LTag=1;
应改为:
while(!
r->
Ltag)r=r->
Lchild;
BiTreeInSucc(BiTreeq){
//已知q是指向中序线索二叉树上某个结点的指针,
//本函数返回指向*q的后继的指针。
r=q->
rchild;
//应改为r=q;
if(!
rtag)
rtag)r=r->
//应改为while(!
Ltag)r=r->
returnr;
//应改为returnr->
rchild;
}//ISucc
3.阅读下列算法,若有错,改正之。
4.画出和下列二叉树相应的森林。
注意根右边的子树肯定是森林,
而孩子结点的右子树均为兄弟。
六、算法设计题
1.编写递归算法,计算二叉树中叶子结点的数目。
思路:
输出叶子结点比较简单,用任何一种遍历递归算法,凡是左右指针均空者,则为叶子,将其打印出来。
法一:
核心部分为:
DLR(liuyu*root)/*中序遍历递归函数*/
{if(root!
=NULL)
{if((root->
lchild==NULL)&
&
(root->
rchild==NULL)){sum++;
printf("
%d\n"
root->
DLR(root->
}
return(0);
法二:
intLeafCount_BiTree(BitreeT)//求二叉树中叶子结点的数目
{
if(!
T)return0;
//空树没有叶子
elseif(!
T->
lchild&
!
rchild)return1;
//叶子结点
elsereturnLeaf_Count(T->
lchild)+Leaf_Count(T->
//左子树的叶子数加
上右子树的叶子数
}//LeafCount_BiTree
上机时要先建树!
例如实验二的方案一。
1打印叶子结点值(并求总数)
先建树,再从遍历过程中打印结点值并统计。
步骤1键盘输入序列12,8,17,11,16,2,13,9,21,4,构成一棵二叉排序树。
叶子结点值应该是4,9,13,21,总数应该是4.
12
717
2111621
4913
编程:
生成二叉树排序树之后,再中序遍历排序查找结点的完整程序如下:
说明部分为:
#include<
stdio.h>
stdlib.h>
typedefstructliuyu{intdata;
structliuyu*lchild,*rchild;
}test;
liuyu*root;
intsum=0;
intm=sizeof(test);
voidinsert_data(intx)/*如何生成二叉排序树?
参见教材P43C程序*/
{liuyu*p,*q,*s;
s=(test*)malloc(m);
s->
data=x;
lchild=NULL;
rchild=NULL;
root){root=s;
return;
p=root;
while(p)/*如何接入二叉排序树的适当位置*/
{q=p;
if(p->
data==x){printf("
dataalreadyexist!
\n"
);
return;
elseif(x<
p->
data)p=p->
elsep=p->
if(x<
q->
data)q->
lchild=s;
elseq->
rchild=s;
main()/*先生成二叉排序树,再调用中序遍历递归函数进行排序输出*/
{inti,x;
i=1;
root=NULL;
/*千万别忘了赋初值给root!
*/
do{printf("
pleaseinputdata%d:
"
i);
i++;
scanf("
%d"
&
x);
/*从键盘采集数据,以-9999表示输入结束*/
if(x==-9999){
DLR(root);
\nNowoutputcountvalue:
sum);
elseinsert_data(x);
}/*调用插入数据元素的函数*/
while(x!
=-9999);
return(0);
执行结果:
若一开始运行就输入-9999,则无叶子输出,sum=0。
2.写出求二叉树深度的算法,先定义二叉树的抽象数据类型。
或编写递归算法,求二叉树中以元素值为x的结点为根的子树的深度。
答;
设计思路:
只查后继链表指针,若左或右孩子的左或右指针非空,则层次数加1;
否则函数返回。
但注意,递归时应当从叶子开始向上计数,否则不易确定层数。
intdepth(liuyu*root)/*统计层数*/
{intd,p;
/*注意每一层的局部变量d,p都是各自独立的*/
p=0;
if(root==NULL)return(p);
/*找到叶子之后才开始统计*/
else{
d=depth(root->
if(d>
p)p=d;
/*向上回朔时,要挑出左右子树中的相对大的那个深度值*/
p)p=d;
p=p+1;
return(p);
intGet_Sub_Depth(BitreeT,intx)//求二叉树中以值为x的结点为根的子树深度
if(T->
data==x)
{
Get_Depth(T));
//找到了值为x的结点,求其深度
exit1;
}
else
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
附:
上机调试过程
层数应当为4
817
步骤2:
执行求深度的函数,并打印统计出来的深度值。
完整程序如下:
voidmain()/*先生成二叉排序树,再调用深度遍历递归函数进行统计并输出*/
\nNowoutputdepthvalue=%d\n"
depth(root));
4.编写按层次顺序(同一层自左至右)遍历二叉树的算法。
或:
按层次输出二叉树中所有结点;
既然要求从上到下,从左到右,则利用队列存放各子树结点的指针是个好办法。
这是一个循环算法,用while语句不断循环,直到队空之后自然退出该函数。
技巧之处:
当根结点入队后,会自然使得左、右孩子结点入队,而左孩子出队时又会立即使得它的左右孩子结点入队,……以此产生了按层次输出的效果。
level(liuyu*T)
/*liuyu*T,*p,*q[100];
假设max已知*/
{intf,r;
f=0;
r=0;
/*置空队*/
r=(r+1)%max;
q[r]=T;
/*根结点进队*/
while(f!
=r)/*队列不空*/
{f=(f+1%max);
p=q[f];
/*出队*/
printf("
p->
/*打印根结点*/
lchild){r=(r+1)%max;
q[r]=p->
}/*若左子树不空,则左子树进队*/
rchild){r=(r+1)%max;
}/*若右子树不空,则右子树进队*/
voidLayerOrder(BitreeT)//层序遍历二叉树
InitQueue(Q);
//建立工作队列
EnQueue(Q,T);
while(!
QueueEmpty(Q))
DeQueue(Q,p);
visit(p);
if(p->
lchild)EnQueue(Q,p->
rchild)EnQueue(Q,p->
}//LayerOrder
可以用前面的函数建树,然后调用这个函数来输出。
完整程序如下
#definemax50
liuyu*root,*p,*q[max];
while(p)/*如何接入二叉排序树的适当位置