第五章 树和二叉树二

合集下载
相关主题
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。


第五章 树和二叉树二、填空题
1.对于一棵具有n个结点的树,该树中所有结点的度数之和为 n-1 。

2.假定一棵三叉树的结点个数为50,则它的最小深度为 5 ,最大深度为 50 。

3.在一棵高度为h的四叉树中,最多含有 4-1/3 h结点。

4.在地棵三叉树中,度为3的结点数有2个,度为2的结点数有1个,度为1的结点数为2个
,那么度为0的结点数有 6 个。

5.一棵深度为5的满二叉树中的结点数为 31 个,一棵深度为3的满四叉树中的结点数为
21 个。

6.假定一棵树的广义表示为A(B(C,D(E,F,G),H(I,J))),则树中所含的结点数为 10
个,树的深度为 4 个,树的度为 3 。

7.假定一棵树的广义表表示为A(B(C,D(E,F,G),H(I,J))),则度为3,2,1,0的结点数分
别为 2 、 1 、 1 和 6 个。

8.假定一棵树的广义表示为A(B(C,D(E,F,G),H(I,J))),则结点H的双亲结点为 B 个,
孩子结点为 I和J 。

9.在一棵二叉树中,假定双亲结点数为5个,单分支结点数为6个,则叶子结点数为 6 个。

10.对于一棵二叉树,若一个结点的编号为i,则它的左孩子结点的编号为 2i ,右孩子
结点的编号为 2i+1 ,双亲结点编号为 i/2 。

11.在一棵二叉树中,第5层上的结点数最多为 16 。

12.假定一棵二叉树的结点数为18,则它的最小深度为 5 ,最大深度为 18 。

13.一棵二叉树的广义表表示为a(b(e,d),e(f(,g))),则e结点的双亲结点为 a ,左孩
子结点为 f ,右孩子结点为 空 。

14.一棵二叉树的广义表表示为a(b(e,d),e(f(,g))),它含有双亲结点 2 个,单分支结
点 2 个,叶子结点 3 个。

15.对于一棵含有40个结点的理想平衡树,它的高度为 6 。

16.假一定一棵二叉树顺序存储在一维数组a中,则a[i]元素的左孩子元素为 a[2i] ,右
孩子元素为 a[2i+1] ,双亲元素(i-1)为 a[i/2] 。

17.假定一棵二叉树顺序存储在一维数组a中,但让编号为1的结点存入a[0]元素中,
让编号为2的结点存入a[1]元素中,其余类推,则编号为i结点的左孩子结点对应的
存储位置为 2i-1 ,若编号为i结点的存储位置用j表示,则其左孩子结点对
应的存储位置为 2j+1 。

18.若对一棵二叉树从0开始进行结点编号,并按此编号把它顺序存储到一维数组a中,
即编号为0的结点存储到a[0]中,其余类推,则a[i]元素的左孩子元素为 a[2i+1] ,
右孩子元素为 a[2i+2] ,双亲元素(i->0)为 a[(i-1)/2] 。

19.对于一棵具有n个结点的二叉树,对应二叉链接表中指针总数为 2n 个,其中
n-1 个用于指向孩子结点, n+1 个指针空闲着。

20.一棵二叉树广义表表示为a(b(d(,h)),c(e,f(g,i(k)))),该树的结点数为 10 个,
深度为 5 。

21.在一棵高度为5的理想平衡树中,最少含

有 16 个结点,最多含有 31 个
结点。

22.在一棵高度为h的理想平衡树中,最少含有 2h-1个结点,最多
含有 2h-1个结点。

23.假定一棵二叉树广义表表示为a(b(c),d(e,f)),则对它进行的先序遍历结果为 a b c d e f
,中序遍历结果为 c b a e d f,后序遍历结果为 c b e f d a,按层遍历结果为 a b
d c e f。

24.假定一棵普通树的广义表表示为a(b((e),c(f(h,i,j),g),d),则先根遍历结果为 a b e c
f h i j g d,按层遍历结果为 a b c d e f g h i j。

二、普通题
1.
解:略

2.
解:略

3.已知一棵度为m的树中有n1个度为1的结点,n2个度为2的结点
,.....,nm个度为m的结点,问树中有多少个叶子结点?
解:
设叶子结点数为n0,则树中结点数和总度数分别为
结点数=n0+n1+n2+...+nm
总度数=n1+2n2+...+m×nm
根据树的性质1可知,结点数等于总度数加1,所以得到
m
n0=1+∑((i-1)×ni)
i=2


4.画出由三个结点a,b,c组成的所有不同结构的二叉树,共有多少种不同的结构?每一种结
构又对应多少种不同的值的排列次序?
解:
由三个结点a,b,c组成的所有不同结构的二叉树如下图所示,共有5种不同的结构,每一
种结构对应6种不同的值的排列次序。
a a a a a
/ \ / / \ \
b c b b b b
/ \ / \
c c c c


5.已知一棵具有n个结点的完全二叉树被顺序存储于一维数组的A[1]~A[n]元素中,试编写一
个算法打印出编号为i的结点的双亲和所有孩子。
解:
void Request(int a[],int n,int i)
//从数组A中打印出编号为i的结点的双亲和孩子
{
if(i>n){
cerr<<"编号为"<exit(1);
}
cout<<"current element:"<int j=i/2; //下标为j的结点是下标为i结点的双亲
if(j>0)
cout<<"parent:"<else
cout<<"树根结点没有双亲结点!"<if(2*icout<<"left child:"<cout<<"right child:"<}
else if(2*i==n){
cout<<"left child:"<cout<<"no right child!"<}
else
cout<<"no children!"<}

6.已知一棵二叉树如下图所示,试分别画出它的不带双亲指针的链接存储结构的示意图和
存储于数组的链接存储映像(假定按层次依次为各结点分配下标位置)。
解:

25
/ \
16 37
/ / \
8 30 48
/ \ \
28 32 60
/ \ \
26 29 35

在数组中的二叉树存储映像如下所示。
0 1 2 3 4 5 6 7 8 9 10 11 12 13 ...BTreeMaxSize

data 25 16 37 8 30 48 28 32 60 26 29 35
left 1 2 4 5 0 7 0 10 0 0 0 0 0
right 13 3 0 6 0 8 9 11 12 0 0 0 0 14 0


7.写出对图5-3所示的二叉树分另按前序、中序、后序遍历时得到的结点序列。
解:
前序遍历为 25,16,8,37,30,28,26,29,32,35,48,60
中序遍历为 8,16,25,26,28,29,30,32,35,37,48,60
后序遍历为 8,16,26,29,28,35,32,30,60,48,37,25

8.写出对二叉树进行中序遍历的非递归算法。
解:
void InorderN(BTreeNode*BT)
//对二叉树进行中序遍历的非递归算法
{
BTreeNode* s[10];//定义用于存储结点指针的栈
int top=-1;定义栈顶指针并赋初值使s栈为空
BTreeNode* p=BT;//定义指针p并使树根指针为它的初值
while(top!=-1||p!=NULL)
{//当栈非空或p指针非空时执行循环
while(p!=NULL){
top++;
s[top]=p;
p=p->left;
}
if(top!=-1){
p=s[top];
top--;
cout<data<<'';
p=p->right;
}
}
}

9.编写一算法,求出一棵二叉树中所有结点数和叶子结点,假定分别用变参C1和C2统计所
有结点数和叶子结点数,初值均为0。
解:
void Count(BTreeNode* BT,int& C1,int& C2)
//分别统计出二叉树中所有结点数和叶子结点数
{
if(BT!=NULL){
C1++;//统计所有结点
if(BT->left==NULL&&BT->right==NULL)
C2++; //统计叶子结点数
Count(BT->left,C1,C2);
Count(BT->right,C1,C2);
}
}

10.编写具有下列功能的每个函数:

把在内存中生成的一棵二叉树写入到一个磁盘文件中,该函数声明为
void WriteFile(char* fname,BTreeNode*BT);
解:
根据从键盘上输入的一棵二叉树广义表表示建立一棵二叉树bt;
把bt二叉树写入到磁盘文件"a:xxkl.dat"中;
把磁盘文件"a:xxkl.dat"中保存的二叉树恢复到内存中,并由bt指向树根结点;
以广义表的形式输出以bt为树根指针的二叉树。
解:
写出先根遍历得到的结点序列;
写出按层遍历得到的结点序列;
画出转换后得到的二叉树和二叉链表。
解:
void WriteFile(char* fname,BTreeNode*BT)
//把由BT指针所指二叉树按照层次遍历的次序存储结点到文件fname中
{
ofstream ofs(fname,ios::binary);

//把由fname所指字符串作为文件名的文件定义为输出文件流ofs,并按二进制方
//式打开
LinkQueue HQ;InitQueue(HQ);
//定义一个链接队列并进行初始化,该链接队列中结点值的类型应为二叉树结点
//的类型
BTreeNode* p;
if(BT!==NULL)QInsert(HQ,BT){
//将树根指针插入到队列中
while(! QueueEmpty(HQ)){
p=QDelete(HQ);
//从队列中删除一个元素并赋给指针
ofs.write((char*)p,sizeof(*p));
//把p指针所指结点写入到文件中
if(p->left!=NULL)QInsert(HQ,p->left);
//若p结点存在左孩子,则左孩子指计入队
if(p->right!=NULL)QInsert(HQ,p->right);
//若p结点存在右孩子,则右孩子指计入队
}
ofs.closs();//关闭文件流对象所对应的文件
}

2.把存储到磁盘文件中的一棵二叉树恢复到内存存中,该函数声明为
void WriteFile(char* fname,BTreeNode*&BT);
解:
void WriteFile(char* fname,BTreeNode*&BT)
//把fname文件中按层扫描存储的二叉树恢复到内存中,并由引用指针BT指向树根结点
{
ifstream ifs(fname,ios::in | ios::nocreate | ios::binary);
//把fname文件定义为输入文件流ifs,并按二进制方式打开
if(! ifs){cout<<"File not open!"<LinkQueue HQ; InitQueue(HQ);
//定义一个链接队列并进行初始化
BTreeNode *p1,*p2;
int b=sizeof(*p1);
//把二叉树结点的大小赋给b,作为读取文件的基本单位
ifs.seekg(0,ios::end);
//把文件指针移到结束位置
int n=ifs.tellg()/b;
//求出文件中所存二叉树的结点数并赋给n
ifs.seekg(0);
//将文件指针移到文件开始位置,以便从头开始读取每个结点
if(n==0){ifs.close();BT=NULL;return;}
//如果文件为空,则把BT置空后返回,用文件中的第一个结点构成树根结点并将
//该结点指针插入队列中
p1=new BTreeNode;
ifs.read((char*)p1,b);
BT=p1;
QInsert(HQ.p1);
n--;
//依次用文件中的每个结点构成新结点并把它插入到双亲结点的左孩子或右孩子位置
while(n)
{ //当读完文件中的结点后循环结束
p2=QDelete(HQ);//从队列中删除队首元素并赋给p2
if(p2->left!=0)
{//需要给p2结点添加左孩子,并使左孩子指针进队
p1=new BTreeNode;
ifs.read((char*)p1,b);
p2->left=p1;
Qinsert(HQ,p1);
n--;
}
if(p2->right!=0)
{ //需要给p2结点添加右孩子,并使右孩子指针进队
p1=new BTreeNode;
ifs.read((char*)p1,b);
p2->right=p1;
QInsert(HQ,p1)
n--;
}
}
ifs.close();//关闭ifs对应的磁盘文件
}

11.编写一个完整的程序实现下列功能:


#include
#include
#include
#include
struct BTreeNode {//定义二叉树结点类型
char data; //定义结点值的类型为整型
BTreeNode *left;
BTreeNode *right;
};
typedef BTreeNode* ElemType;//定义链接队列中结点值的类型为二叉树结点的指针类型
struct LNode{ElemType data;LNode* next;};
//定义链接队列中结点的类型
struct LinkQueue{LNode* front;LNode*rear;};
//定义一个链接队列的存储类型
#include"linkqueue.h"//包含对链接队列的各种运算
#include"btree.h"//包含二叉树的各种运算
void WriteFile(char* fname,BTreeNode* BT)
//把由BT指针所指二叉树按照层次遍历的次序存储结点到文件fname中
{
//函数体略
}
void ReadFile(char* fname,BTreeNode*&BT)
//把fname文件中按层扫描存储的二叉树恢复到内存中,并由引用指针BT
//指向树根结点
{
//函数体略
}
void main()
{
BtreeNode *bt;
InitBTree(bt);
while(1)
{
cout<<"功能菜单:"<cout<<'\t'<<"1.建立二叉树"<cout<<'\t'<<"2.二叉树存盘"<cout<<'\t'<<"3.由文件恢复二叉树"<cout<<'\t'<<"4.以广义表形式输出二叉树"<cout<<'\t'<<"5.结束程序运行"<cout<int m;
cout<<"输入你的选择(1-5):";
do cin>>m;while(m<1||m>5);
switch(m){
case 1:
char a[50];
cout<<"输入以'@'字符作为结束符的二叉树广义表表示:"<cin>>ws;//跳过键盘输入缓冲区中的空白字符
cin.getline(a,50);
createBTree(bt,a);
break;
case 2:
WriteFile("a:xxkl.dat",bt);
break;
case 3:
ReadFile("a:xxkl.dat",bt);
break;
case 4:
PrintBTree(bt);cout<break;
default;
break;
}
if(m==5)break;
}
}

12.对于图5-16所示的树:


13.假定一棵树采用标准形式存储,试写出广义表形式输出树的算法。
解:
void printGTree(GTreeNode* GT)
//以广义表形式输出按标准方式存储的三叉树
{
if(GT!=NULL){//若树不为空则进行如下处理
cout<data<<'';//输出根结点的值
if(GT->t[0]||GT->t[1]||GT->t[2]){
cout<<'(';
printGTree(GT->t[0]);//输出第一棵子树
cout<<',';
printGTree(GT->t[1]);//输出第二棵子树
cout<<',';
printGTree(GT->t[2]);//输出第三棵子树
cout<<')';
}
}
}

14.假定采用标准形式存储,试写出求其深度的算法。
解:
int GTreeDepth(GTreeNode* GT)
//求一棵普通树的深度
{
if(GT==

NULL)//空树的深度为0
return 0;
else{
int max=0;//用来保存子树中的最大深度
for(int i=0;i<3;i++){
int d=GTreeDepth(GT->t[i]);
//计算出一棵子树的深度并赋给变量d
if(d>max)max=d;
}
return max+1; //返回树的深度,它等于子树的最大深度加1
}
}

10.在一份电文中共使用五种字符:a、b、c、d、e ,它们的出现频率依次为4、7、5、2、9
,试画出对应的编码哈夫曼树(请按照左子树根结点的权小于等于右子树根结点的权的次序构
造),求出每个字符的哈夫曼编码,并求出传送电文的长度。
解:
五种字符的哈夫曼编码依次为001,10,00,010,11。传送电文的总长度为60。



类别:数据结构.

相关文档
最新文档