数据结构电子教案 第六章.docx
《数据结构电子教案 第六章.docx》由会员分享,可在线阅读,更多相关《数据结构电子教案 第六章.docx(28页珍藏版)》请在冰豆网上搜索。
数据结构电子教案第六章
同步综合练习及参考答案
(一)基础知识题
6.1加设在树中,结点x是结点y的双亲时,用(x,y)来表示树变。
已知一棵树边的集合为:
{(i,m),(i,n),(b,e),(e,i),(b,d),(a,b),(g,i),(g,k),(c,g),(c,f),(h,l),(c,h),(a,c)}用树形表示法画出此树,并回答下列问题:
(1)哪个是根结点?
(2)哪些是叶结点?
(3)哪个是g的双亲?
(4)哪些是g的祖先?
(5)哪些是g的孩子?
(6)哪些是e的子孙?
(7)哪些是e的兄弟?
哪些是f的兄弟?
(8)结点b和n的层次各是多少?
(9)树的深度是多少?
(10)以结点c为根的子树的深度是多少?
(11)树的度数是多少?
解:
(1)a是根结点。
(2)m,n,j,k,l是叶结点。
(3)c是g的双亲。
(4)a,c是g的祖先。
(5)g的孩子是j,k.。
(6)e的子孙是i,m,n.。
(7)e的兄弟是a,f的兄弟是g。
(8)h,b在第五层。
(9)树的深度为3。
(10)以C为根的子树的深度为3。
(11)树的度数为3。
6.2一棵度为2的有序属于一棵二叉树有何区别?
解:
区别:
度为2的树有二个分支,没有左右之分;以可二叉树也有两个分支,但有左右之分,且左右不能交换。
6.3试分别画出具有3个结点的树和3个结点的二叉树的所有不同形态。
解:
3个结点树形态:
3个结点的二叉树:
6.4已知一棵树为m的树中有n1个度为1的结点,n2个度为2的结点,…nm个度为m的结点,问该书中有多少片叶子?
解:
因为n1+n2+…+nM+n0+=1+n1+2n2+…+mnM
=>n0+=1+n2+…+(m-1)nM
6.5一个深度为h的满k叉树有如下性质:
第h层上的结点都是叶子结点,其余各层上每个结点都有k棵非空子树。
如果按层次顺序(同层自左至右)从未有过开始对全部结点编号,问:
(1)各层的结点数目是多少?
(2)编号为i的结点的双亲结点(若存在)的编号是多少?
(3)编号为i的结点的第j个孩子结点(若存在)的编号是多少?
(4)编号为i的结点有右兄弟的条件是什么?
其右兄弟的编号是多少?
解:
(1)Ki-1
(2)
(3)Ki+j-1
(4)(i-1)MODK<>0,i+1
6.6高度为h的完全二叉树至少有多少个结点?
至多有多少个结点?
解:
至少有:
2h-1,至多有:
2h-1
6.7在具有n个结点的k叉树(k≥2)的k叉树链表表示中,有多少个空指针?
解:
(k-1)n+1个空指针
6.8假设二叉树包含的结点数据为1,3,7,2,12。
(1)画出两棵高度最大的二叉树;
(2)画出两棵完全二叉树,要求每个双亲结点的值大于其孩子结点的值。
6.9试找出分别满足下面条件的所有二叉树:
(1)前序序列和中序序列相同;
(2)中序序列和后序序列相同;
(3)前序序列和后序序列相同;(4)前序、中序、后序序列均相同。
解:
(1)空二叉树或任一结点均无左子树的非空二叉树
(2)空二叉树或任一结点均无左子树的非空二叉树
(3)空二叉树或仅有一个结点的二叉树
(4)同(3)
6.10试采用顺序存储方法和链接存储方法分别画出6.30所示各二叉树的存储结构。
解:
①顺序存储:
(a)12φφ3φφφφ4φφφφφφφφφφ5
(b)1φ2φφ3φφφφφφφ4φφφφφφφφφφφφ5
(c)1φ2φφ34φφφφ56φφφφφφφφφφφ78
(d)1234φ56φ7φφφφ89
②连接存储:
6.11分别写出图6.30所示各二叉树的前序、中序和后序序列。
解:
6.12若二叉树中个结点的值均不相同,则由二叉树的前序序列和中序序列,或由其后序序列的中序列均能惟一地确定一棵二叉树,但由前序序列和后序序列却不一定能惟一地确定一棵二叉树。
(1)已知一棵二叉树的前序序列和中序序列分别为ABDGHCEFI和GDHBAECIF,请画出此二叉树。
(2)已知一棵二叉树的中序序列和后序序列分别为BDCEAFHG和DECBHGFA,请画出此二叉树。
(3)已知两棵二叉树前序序列和后序序列均为AB和BA,请画出这两棵不同的二叉树。
解:
6.13对二叉树中结点进行按层次顺序(每一层自左至右)的访问操作称为二叉树的层次遍历,遍历所得到的结点序列称为二叉树的层次序列。
现已知一棵二叉树的层次序列为ABCDEFGHIJ,中序序列为DBGEHJACIF,请画出该二叉树。
解:
6.14试画出图6.30所示各二叉树的前序、中序和后序线索树及相应的线索链表。
解:
(以c为例)
1前序:
12357864
2前序:
17583624
6.15在何种线索树中,线索对所求指定结点在相应次序下的前趋和后继并无帮助?
解:
在前序线索树中找某一点的前序前趋以及在后序线索树中寻找某一点的后继,线索并无多大帮助。
6.16对图6.31所示的森林:
(1)求各树的前序序列和后序序列:
(2)求森林的前序序列和后序序列:
(3)将此森林转换为相应的二叉树:
(4)给出(a)所示树的双亲链表表示、孩子链表表示、双亲孩子链表表示及孩子兄弟链表表示等四种存储结构,并指出哪些存储结构易于求指定结点的祖先,哪些易于求指定结点的后代?
解:
(1)abc
前序ABCDEFGHIJKLMPQRNO
后序BDEFCAIJKHGQRPMNOL
(2)前序:
ABCDEFGHIGKLMPQRNO
后序:
BDEFCAIJKHGQRPMNOL
(3)二叉树
(4)1
1孩子链表表示发:
2双亲链表表示发:
结点0123456
dataABCDEF
parent-1011333
3双亲孩子链表:
4孩子兄弟链表表示:
5易于求祖先:
双亲链表面双亲孩子
6易于求后代:
孩子链表双亲孩子
6.17画出图6.32所示的各二叉树所应的森林
6.18高度为h的严格二叉树至少有多少个结点?
至多有多少个结点?
解:
最多有2n-1最少有2n-1
6.19在什么样的情况下,等长编码是最优的前缀码?
解:
当字符集中的各字符使用频率均匀时。
6.20下属编码哪一组不是前缀码?
{00,01,10,11},{0,1,00,11},{0,10,110,111}
解:
因为前缀码中不可能存在一个元素是另一个的前面部分。
所以第二组不是。
6.20假设用于通信的电子由字符集{a,b,c,d,e,f,g,h}中的字母构成,这8个字母在电文中出现的概率分别为{0.07,0.19,0.02,0.06,0.32,0.03,0.21,0.10}
(1)为这8个字母设计哈夫曼编码。
(2)若用三位二进制数(0~7)对这个8个字母进行等长编码,则哈夫曼编码的平均码长是等长编码的百分之几?
它使电文总长平均压缩多少?
解:
①
②哈夫曼编码码长:
4*0.07+2*0.19+5*0.02+4*0.06+5*0.03+2*0.21+4*0.1=2.71
等长码长:
3
905平均缩了10%
(二)算法设计题
6.22二叉树的遍历算法可写为通用形式。
例如,通用的中序遍历为:
voidInorder(BinTreeT,void(*Visit)(Datatypex))
{if(T)
{Inorder(T->lchild,Visit);/*遍历左子树*/
Visit(T->data);/*通过函数指针调用它所指的函数来访问结点*/
Inorder(T->rchild,Visit);/*遍历右子树*/
}
}
其中Visit是一个函数指针,它指向形如voidf(DdataTypex)的函数。
因此我们可以将访问结点的操作写在函数f中,通过调用语句Inorder(root,f)将f的地址传递给Visit,来执行遍历操作。
请写一个打印结点的数据的函数,通过调用上述算法来完成书中6.3节的中序遍历。
解:
#include“stdio.h”
#defineNull0
typedefcharDataType;
typedefstructnode
{
DataTypedata;
Structnodelchild,rchild;
}BinTree;
BinTree*root;
BinTree*Q[100];
BinTreeCreateBinTree()/*建立二叉树*/
{
charch;
intfront,rear;
BinTreeroot,s;
Root=Null;
front=1;
rear=0;
ch=getchar();
while(ch!
=’#’)
{
s=Null;
if(ch!
=’@’)
{
s=(BinTree*)malloc(sizeof(BinTree));
s->data=ch;
s->lchild=Null;
s->rchild=Null;
}
rear++;
Q[rear]=s;
if(rear==1)root=s;
else
{
if(s&&Q[front])
if(rear%2==0)Q[front]->lchild=s;
else
Q[front]->rchild=s;
if(rear%2==1)front++;
}
ch=getchar();
}
returnroot;
}
main()
{
root=CreateBinTree();
Inorder(root);
}
1中序遍历法之一
Inorder(BinTree*t)
{
if(t)
{
Inorder(t->lchild);
Visit(t->data);
Inorder(t->rchild);
}
}
Vist(inti)
{
printf(“%c”,i);
}
2中序遍历法之二
Inorder(BinTree*t)
{
if(t)
{
Inorder(t->lchild);
printf(“%c”,t->data);
Inorder(t->rchild);
}
}
6.23以二叉链表为存储结构,分别写出求二叉树结点总数及叶子总数的算法。
解:
1计算结点总数
intCountNode(BinTree*root)
{
intnum1,num2;
if(root==Null)return(0);
elseif(root->lchild==Null&&rooot->rchild==Null)
return
(1);
else
{
num1=CountNode(root->lchild);
num2=CountNode(root->rchild);
return(num1+num2+1);
}
}
2计算叶子总数
intCountLeafs(BinTree*root)
{
intnum1,num2;
if(root==Null)return(0);
elseif(root->lchild==Null&&root->rchild==Null)
return
(1);
else
{
num1=CountLeafs(root->lchild);
num2=CountLeafs(root->rchild);
return(num1+num2);
}
}
6.24以二叉链表为存储结构,分别写出求二叉树高度及宽度的算法。
所谓宽度是指在二叉树的各层上,具有结点数最多的那一层上的结点总数。
解:
1求树的高度
思想:
对非空二叉树,其深度等于左子树的最大深度加1。
IntDepth(BinTree*T)
{
intdep1,dep2;
if(T==Null)return(0);
else
{
dep1=Depth(T->lchild);
dep2=Depth(T->rchild);
if(dep1>dep2)return(dep1+1);
elsereturn(dep2+1);
}
2求树的宽度
思想:
按层遍历二叉树,采用一个队列q,让根结点入队列,最后出队列,若有左右子树,则左右子树根结点入队列,如此反复,直到队列为空。
intWidth(BinTree*T)
{
intfront=-1,rear=-1;/*队列初始化*/
intflag=0,count=0,p;
/*p用于指向树中层的最右边的结点,标志flag记录层中结点数的最大值。
*/if(T!
=Null)
{
rear++;
q[rear]=T;
flag=1;
p=rear;
}
while(front
{
front++;
T=q[front];
if(T->lchild!
=Null)
{
rear++;
q[rear]=T->lchild;
count++;
}
if(T->rchild!
=Null)
{
rear++;
q[rear]=T->rchild;
count++;
}
if(front==p)/*当前层已遍历完毕*/
{
if(flagcount=0;
p=rear; /*p指向下一层最右边的结点*/
}
}/*endwhile*/
return(flag);
}
6.25以二叉链表为存储结构,写一算法交换各结点的左右子树。
解:
思想:
借助栈来进行对换。
Swap(BinTree*T)
{
BinTree*stack[100],*temp;
inttop=-1;
root=T;
if(T!
=Null)
}
top++;
stack[top]=T;
while(top>-1)
{
T=stack[top];
top--;
if(T->child!
=Null||T->rchild!
=Null)
{/*交换结点的左右指针*/
temp=T->lchild;
T->lchild=T->rchild;
T->rchild=temp;
}
if(T->lchild!
=Null)
{
top++;
stack[top]=T->lchild;
}
if(T->rchild!
=Null)
{
top++;
stack[top]=T->rchild;
}
}
}/*endwhile*/
}/*endif*/
main()
{
intI,j,k,l;
printf(“\n”);
root=CreateBinTree();
Inorder(root);
i=CountNode(root);
j=CountLeafs(root);
k=Depth(root);
l=Width(root);
printf(“\nTheNode’sNumber:
%d”,i);
printf(“\nTheLeafs’sNumber:
%d”,j);
printf(“\nTheDepthis:
%d”,k);
printf(“\nThewidthis:
%d”,l);
Swap(root);
Printf(“\nTheswapTreeis:
”);
Inorder(root);
}
6.26以二叉表为存储结构,写一个拷贝二叉表的算法哦(BinTreeroot,BinTree*newroot),其中新树的结点是动态申请的,为什么newroot要说明为BinTree形指针的指针?
解:
CopyTree(BinTreeroot,BinTree*(newroot))
}
if(root!
=Null)
{
*newroot=(BinTree*)malloc(sizeof(BinTree));
(*newroot)->data=root->data;
CopyTree(root->lchild,&(*newroot)->lchild);
CopyTree(root->rchild,&(*newroot)->rchild);
Inorder(*newroot);
}
elsereturn(Null);
}
main()
{
BinTree*newroot;
intI,j,k,l;
printf(“\n”);
root=CreateBinTree();
Inorder(root);
Printf(“\n”);
/*Swap(root);*/
&(*newroot)=Null;
CopyTree(root,&*newroot);
}
6.27以二叉树表为存储结构,分别写处在二叉树中查找值为x的结点在树中层数的算法。
解:
inth=-1,lh=1,count=0;charx=’c’;/*赋初值*/
Level(BinTreeT,inth,intlh)/*求X结点在树只的层树*/
{
if(T==Null)h=0;
elseif(T->data==x)
{
h=lh;
count=h;
}
else
{
h++;
Level(T->lchild,h,lh);
If(h==-1)Level(T->rchild,h,lh);
}
}
main()
{
BinTree*(*newroot);
Printf(“\n”);
Root=CreateBinTree();
Inorder(root);
Printf(“\n”);
Level(root,h,lh);
Printf(“%d”,count);
}
6.28一棵n个结点的完全二叉树以向量作为存储结构,试写一非递归算法实现对该树的前序遍历。
解:
思想:
采用栈,先让跟结点如栈,然后退栈,如有左右孩子,则先让右孩子如栈,然后左孩子如栈,如此反复实现前序遍历。
typedefstruct
{
intdata[100];
inttop;
}seqstack;
seqstack*s;
Perorder(chara[],intn)
{
inti=1,count=1;
s->top=-1;
if(n==0)return(0);
else
{
if(I<=n)
{
s->top++;
s->data[s->top]=a[I];
}
while(count{
printf(“%c”,s->data[s->top]);
count++;
s->top--;
if(s->data[s->top]);==a[i])
{/*若栈顶结点为a[i]结点,则退栈,保证父结点比孩子结点先退栈*/
printf(“%c”,s->data[s->top]);
count++;
s->top--;
}
if((2*i+1){
i=2*i;
s->top++;
s->data[s->top]=a[i+1];
s->top++;
s->data[s->top]=a[i];
}
elseif(a*i{
i=2*i;
s->top++;
s->data[s->top]=a[i];
}
elseif(i/2%2==1)i=i/2/2+1;
/*父结点没有右兄弟,回到祖父结点大右兄弟*/
elsei=i/2+1;/*回到父结点的右兄弟*/
}
}
}
main()
{
charA[]=“kognwyuvb”;
intn=strlen(A);
s=(seqstack*)malloc(sizeof(seqstack));
printf(“\n”);
Perorder(A,n);
}
6.29以二叉树表为存储结构,写一算法对二叉树进行层次遍历(定义见习题6.13)。
提示:
应使用队列来保存各层的结点。
解:
voidTransLevel(BinTree*T)
{
intfront=0,rear=0;
intp;
if(T!
=Null)
{
printf(“%c”,T->data);
q[rear]=T;
rear++;
}
while(front{
T=q[front];
Front++;
if(T->lchild!
=Null)
{
printf(“%c”,T->lchild->data);
q[rear]=T->lchild;
rear++;
}
if(T->rchild!
=Null)
{
printf(“%c”,T->rchild->dara);
q[rear]=T->rchild;
rear++;
}
}
}
main()
{
printf(“\n”);
root=CreateBinTree();
Inorder(root);
Printf(“\n”);
TransLevel(root);
}
6.30以二叉树表为存储结构,写一算法用括号形式(keyLT,RT)打印二叉树,其中key是根结点数据,LT和RT分别是括号形式的左右子树。
并且要求:
空树不打印任何信息,一给结点x的树打印形式是x,而不应是(x,,)d的形式。
解:
viodPrint(BinTreeT)/*哟感括号形式打印二叉树*/
{
if(T!
=Null)
{
if(T->lchild==Null&&T->rchild==Null)/*只有根结点*/
printf(“%c”,T->data);
else/*T->lchild!
=Null||T->rchild!
=Null*/
{
printf(“(”);
printf(“%c”,T->data);
if(T->lchild->lchild==Null&&T->lchild->rchild==Null)
printf(“)”);
Print(T->lchild);
if(T->rchild!
=Nulll)printf(“,”);
printf(“)”);
printf(“)”);
}
}
}
mai