数据结构课后习题答案解析第六章.doc
.第六章树和二叉树下载后用阅读版式视图或web版式可以看清习 题一、选择题 1有一"遗传"关系:设x是y的父亲,则x可以把它的属性遗传给y。表示该遗传关系最适合的数据结构为< >。 A.向量 B.树 C图 D.二叉树 2树最合适用来表示< >。 A.有序数据元素 B元素之间具有分支层次关系的数据 C无序数据元素 D.元素之间无联系的数据 3树B的层号表示为la,2b,3d,3e,2c,对应于下面选择的< >。 A. la <2b <3d,3e>,2c> B. a<b<D,e>,c> C. a<b<d,e>,c> D. a<b,d<e>,c> 4.高度为h的完全二叉树至少有< >个结点,至多有< >个结点。 A. 2h_l B.h C2h-1 D. 2h 5.在一棵完全二叉树中,若编号为f的结点存在右孩子,则右子结点的编号为< >。 A. 2i B. 2i-l C. 2i+l D. 2i+2 6.一棵二叉树的广义表表示为a<b<c>,d<e<,g<h>>,f>>,则该二叉树的高度为 < >。 A.3 B.4 C.5 D.6 7.深度为5的二叉树至多有< >个结点。 A. 31 B. 32 C. 16 D. 10 8.假定在一棵二叉树中,双分支结点数为15,单分支结点数为30个,则叶子结点数为< >个。 A. 15 B. 16 C. 17 D. 47 9.题图6-1中,< >是完全二叉树,< >是满二叉树。 10.在题图6-2所示的二叉树中: <1>A结点是 A.叶结点 B根结点但不是分支结点 C根结点也是分支结点 D.分支结点但不是根结点 <2>J结点是 A.叶结点 B根结点但不是分支结点 C根结点也是分支结点 D.分支结点但不是根结点 <3>F结点的兄弟结点是 A.E B.D C空 D.I <4>F结点的双亲结点是 A.A B.B C.C D.D <5>树的深度为 A.1 B.2 C.3 D.4 <6>B结点的深度为 A.1 B.2 C.3 D.4 <7>A结点所在的层是 A.1 B.2 C.3 D.4 11.在一棵具有35个结点的完全二叉树中,该树的深度为< >。 A.5 B.6 C.7 D.8 12. 一棵有124个叶结点的完全二叉树,最多有< >个结点。 A247 B248 C249 D250 13.用顺序存储的方法将完全二叉树中所有结点逐层存放在数组R1n中,结点Ri若有左子树,则左子树是结点< >。 A. R2i+l B. R2i C.Ri/2 D. R2i-1 14.在一非空二叉树的中序遍历序列中,根结点的右边< >。 A.只有右子树上的所有结点 B.只有右子树上的部分结点 C.只有左子树上的部分结点 D.只有左子树上的所有结点 15一棵度为m的树中,有ni个度为1的结点,有n2个度为2的结点,有nm个度为m的结点,则该树的叶结点数为< >。 A. n1+n2+.+nm B. <m-l> nm+.+n2+1 C.n1+n2+1 D. nl-n2 16.已知某二叉树的中序遍历序列是debac,后序遍历序列是dabec,它的前序遍历序列是< >。A. acbed B. decab C. deabc D. cedba17.在一棵二叉树的二叉链表中,空指针域等于所有非空指针域数加< >。 A.2 B.1 C.0 D.-118.线索二叉树是一种< >结构。 A.逻辑 B逻辑和存储 C物理 D.线性19.由权值分别是8,7,2,5的叶子结点生成一棵哈夫曼树,它的带权路径长度为< >。 A. 23 B. 37 C46 D. 4320.设T是哈夫曼树,具有5个叶结点,树T的高度最高可以是< >。 A.2 B.3 C.4 D.5二、填空题1.对于一棵具有n个结点的树,该树中所有结点的度数之和为_。2.在树型结构中,树根结点没有_结点,其余每个结点有且只有_个前驱结点:叶子结点没有_结点,其余每个结点可以有_后继结点。3.有一棵树如题图6-3所示,回答下面的问题。 这棵树的根点是_;叶子结点是_;结点k3的度是_;结点k3的子女是_;结点k3的父结点是_;这棵树的度为_;这棵树的深度是_。4.假定一棵树的广义表表示为A<B<E>,C<F<H,I,J,G>,D>,则该树的度为_,树的深度为_,终端结点的个数为_,单分支结点的个数为_,双分支结点的个数为_,3分支结点的个数为_,C结点的双亲结点为_,其孩子结点为_。5.一棵深度为h的满k叉树有如下性质:第h层上的结点都是叶子结点,其余各层上的每个结点都有k棵非空子树。如果按层次顺序同层自左至右从1开始对全部结点编号,则: <1>第i层结点数目是_。 <2>编号为n的结点的双亲结点若存在的编号是_。 <3>编号为n的结点的第i个孩子结点若存在的编号是_。 <4>编号为n的结点有右兄弟的条件是_:其右兄弟的编号是_。6前序遍历一棵树相当于_树中对应的二叉树,后序遍历一棵树则相当于树中对应的二叉树。 7二叉树的遍历分为_ ,树与森林的遍历包括_。8一棵二叉树的第i<i>=1>层最多有_个结点;一棵有n<n>0>个结点的满二叉树共有_ 个叶子和_个非终端结点。9.在一棵二叉树中,假定双分支结点数为5个,单分支结点数为6个,则叶子结点为_个。10在一棵二叉树中,第五层上的结点数最多为_。11.对于一棵具有n个结点的二叉树,当进行链接存储时,其二叉链表中的指针域的总数为_个,其中_个用于链接孩子结点,_个空闲着。12.前序遍历的顺序是ABDGEHICFJ,则二叉树的根是_。13.从概念上讲,树与二叉树是两种不同的数据结构,将树转化为二叉树的基本目的是_14.结点最少的树为_ ,结点最少的二叉树为_。15.一棵完全二叉树按层次遍历的序列为ABCDEFGHI,则在前序遍历中结点E的直接前驱为_ ,后序遍历中结点B的直接后继是_。16.某二叉树的中序遍历序列为ABCDEFG,后序序列为BDCAFGE,则该二叉树结点的前序序列为_,该二叉树对应的森林包括_棵树。17.用一维数组存放的一棵完全二叉树如题图6-4所示。 则后序遍历该二叉树时结点访问的顺序为_。18.由n个权值构成的哈夫曼树共有_个结点。19.由带权为3,9,6,2,5的5个叶子结点构成一棵哈夫曼树,则带权路径长度为_。20.设F是一个森林,B是由F转换得到的二叉树,F中有n个非终端结点,则B中右指针域为空的结点有_个。21.二叉树的存储结构分为_ ,树的存储结构分为_。三、判断题1树中任意结点的子树不必是有序的。< >2树可以看成特殊的无向图。< >3可以使用双链表表示树型结构。< >4顺序存储方式只能用于存储线性结构。< >5完全二叉树的某结点若无左孩子,则必是叶结点。< >6在叶子数目和权值相同的所有二叉树中,最优二叉树一定是完全二叉树。< >7由于二叉树中每个结点的度最大为2,所以二叉树是一种特殊的树。< >8二叉树的前序遍历序列中,任意一个结点均处在其子树结点的前面。 < >9二叉树的前序和后序遍历序列能惟一确定这棵二叉树。 < >10.中序线索二叉树中,右线索若不为空,则一定指向其父结点。< >四、算法和操作题1假定一棵二叉树广义表表示为a<b<c>,d<e,D>,分别写出对它进行前序、中序、后序遍历的结果。 前序: 中序: 后序:2已知一棵二叉树的中序和后序序列,求该二叉树的高度和双支、单支及叶子结点数。 中根序列:c,b,d,e,a,g,i,h,j,f 后根序列:c,e,d,b,i,j,h,g,fa 高度: 双支: 单支: 叶子: 3已知一棵树边的集合为<I< SPAN>,M>,<I< SPAN>,N>,<E< SPAN>,I>,<B< SPAN>,E>,<B< SPAN>,D>,<A< SPAN>,B>,<G< SPAN>,J>,<G< SPAN>,K>,<C< SPAN>,G>,<C< SPAN>,F>,<H< SPAN>,L>,<C< SPAN>,H>,<A< SPAN>,C>>,请画出这棵树,并回答下列问题: <1>哪个是根结点? <2>哪些是叶子结点? <3>哪个是结点G的双亲? <4>哪些是结点G的祖先? <5>哪些是结点G的孩子? <6>哪些是结点E的子孙? <7>哪些是结点E的兄弟?哪些是结点F的兄弟? <8>结点B和N的层次号分别是什么? <9>树的深度是多少? <10>以结点C为根的子树的深度是多少?4将算术表达式<<a+b>+c*<d+e>+f*<g+h>转化为二叉树。5. 一棵二叉树的结点数据采用顺序存储结构,存储于数组BT中,如题表6-1所示。画出该二叉树的链接表示形式。数组BT的存放形式是相对于满二叉树中编号为数组下标值的结点值。若该结点不存在,则取0值。 6假设前序遍历某棵树的结点次序为SACEFBDGHIJK;后序遍历该树的结点次序为CFEABHGIKJDS,请画出这棵树。7已知一棵树如题图6-5所示,将其转换为其孩子兄弟表示的二叉树。并画出该二叉树的后序线索二叉树。8试找出分别满足下列条件的所有二叉树: <1>前序遍历序列和中序遍历序列相同。 <2>中序遍历序列和后序遍历序列相同。 <3>前序遍历序列和后序遍历序列相同。9已知信息为"ABCD BCD CB DB ACB",请按此信息构造哈夫曼树,求出每一字符的最优编码。10.己知中序线索二叉树采用二叉链表存储结构,链结点的构造为:其中若ltag为0,则lchild指向结点的前驱,否则lchild指向左孩子结点;若rtag为0,则rchild指向结点的后继,否则rchild指向右孩子结点。下面的算法返回x所指结点的直接后继结点的位置。若该算法有错,则请改正错误;若无错,请写"正确"二字。 BiTree INSUCC <BiTree x> s=X->rchild; ifs->rtag while s->ltag s=s->rchild; return s; >五、算法设计题1编写对二叉树进行中序遍历的非递归算法,并对算法执行题图6-6所示的二叉树的情况进行跟踪即给出各阶段栈的变化及输出的结点序列。栈已经定义:InitStack<S>初始化、Empty<S>判栈空、Push<S,p>入栈、Pop<S,p>出栈等操作。2假设在表示一棵二叉树的二叉链表上增加两个域:双亲域用于指示其双亲结点,标志域flag可取0.2的值,用以区分在遍历过程中到达该结点时继续向右或向左或访问该结点。试以此存储结构编写不用栈进行后序遍历的递归形式的算法。3一棵具有n个结点的完全二叉树,以一维数组作为存储结构,试设计一个对该完全二叉树进行前序遍历的算法。4设中序线索树的结点由5个域组成。 Info:给出结点的数据域。 LT:标志域,为0或1。 LL:当LT为1时,给出该结点的左孩子的地址。 当LT为0时,给出按中序遍历的前驱结点地址。 RT:标志域,为0或1。 RL:当 RT为1时,给出该结点的右孩子的地址。 当RT 为O时,给出按中序遍历的后继结点地址。 请编写 程序,在具有上述结点结构的中序线索二叉树上,求某一结点p按后序遍历次序的后继结点的地址q,设该中序线索二叉树的根结点地址为r。 另外,请注意必须满足: <l>额外空间的使用只能为O<1>。 <2>程序为非递归形式。5假设二叉树采用链接方法存储,编写一个函数按凹入表表示法打印出该二叉树。6给出中序线索树的结点结构,设计算法在不使用栈和递归的情况下前序遍历一棵中序线索树,并分析它的时间复杂度。7以二叉链表为存储结构,写出交换各结点左右子树的算法。8假设二叉树采用链接方法存储,编写一个函数按凹入表表示法打印出该二叉树。第六章 树和二叉树第6章树和二叉树 一、选择题参考答案 1B2B3C 4A,C 5C 6C7A8B 9A,B 10. <1>C <2>A <3>C <4>A <5>C <6>A <7>C 11B 12.A13B 14A15B 16D 17A 18C 19D 20D 二、填空题参考答案 1树的总结点数-1。 2前驱:1,后继,任意多个。 3. kl, k2, k4, k5, k7,2,k5, k6, kl,3,4。 4.3,4,6,1,1,2,A,F,G。 5.<1> ki-l, <2> ëû, <3> n-l×k+n+1,<4>ink+l<n=0,l,2,>,n+1. 6前序遍历,中序遍历。 7前序,中序,后序,前序,后序。 8. 2i-1,2/n,ë2/nû. 9.6个。 10. 160 11. 2n,n-l,n+l。 12A 13.树可采用二叉树的存储结构并可利用二叉树的已有算法解决树的有关问题。 14.只有1个结点的树,空树。 15.I,F。 16.前序遍历序列为:EACBDGF,森林包括1棵树。 17. HIDJKEBLFGCA0 18. 2n-l。 19. 560 20n+l。 21.顺序存储和链式存储,双亲链表表示法,孩子链表表示法,孩子兄弟链表表示法 三、判断题 1. 2. 3. 4.× 5. 6.× 7.× 8. 9.× 10.× 四、算法和操作题 1假设一棵二叉树广义表表示为a<b<c>,d<e,D>,分别写出对它进行前序、中序、后序遍历的结果。 解答前序:a,b,c,d,e,D 中序:c,b,a,e,d,D 后序:c,b,e,D,d,a 2已知一棵二叉树的中序和后序序列,求该二叉树的高度和双支、单支及叶子结点数。 解答中序序列:c,b,d,e,a,g,i,h,j,f 后序序列:c,e,d,b,i,j,h,g,f,a 由中序和后序前序遍历序列可惟一确定一棵二叉树,基本思想是后序前序定根,中序分左右。由后序序列可知该树的根结点为a,由中序遍历序列可知该树的左子树为c,b,d,e,右子树为g,i,h,j,f;再由后序序列可知该树的左子树的根结点为b,右子树的根结点为f再由中序遍历序列可知b结点的左子树为c,右子树为d,e;再由后序遍历序列可知右子树d,e的根结点为d,再由中序遍历序列可知d的左子树为空,右子树为e。对以f为根结点的子树可做类似的分析。最后得到由中序和后序序列决定的二叉树为: a<b<c,d<,e>>,f<g<,h<i,j>>>>,由此可知该树: 高度:5 双分支:3 单分支:3 叶结点:4。 3已知一棵树边的集合为<I,M>,<I,N>,<E,I>,<B,E>,<B,D>,<A,B>,<GJ>,<G K>,<C,G>,<C,F>,<H,L>,<C,H>,<A,C>,请画出这棵树,并回答问题?解答根据边集画出的树如下所示: <1>根结点是:A。 <2>叶子结点是:D,M,N,F,J,K,L。 <3>结点G的双亲是:C。 <4>结点G的祖先是:A,C。 <5>结点G的孩子是:J,K。 <6>结点E的子孙是:I,M,N。 <7>结点E的兄弟是:D;结点F的兄弟是:G,H。 <8>结点B和N的层次号分别是:2,5。 <9>树的深度是:5。 <10>以结点C为根的子树的深度是:3。 4将算术表达式<<a+b>+c*<d+e>+f*<g+h>转化为二叉树。 解答转化成如下二叉树: 5-棵二叉树的结点数据采用顺序存储结构,存储于数组BT中,如题表6-1所示。画出该二叉树的链接表示形式。数组BT的存放形式是相对于满二叉树中编号为数组下标值的结点值。若该结点不存在,则取0值。题表6-1解答二叉树的链式表示为: 6若前序遍历某树的结点次序:SACEFBDGHIJK;后序遍历的结点次序为:CFEABHGIKJDS,画出这棵树。 解答画出树如下: 7将原教材题图6-5转换为孩子兄弟所表示的二叉树及该二叉树的后序线索二叉树如下: 8空树满足所有条件。非空树如下: <1>前序和中序遍历序列相同的二叉树是没有左子树的二叉树右单支树。 <2>中序和后序遍历序列相同的二叉树是没有右子树的二叉树左单支树。 <3>前序和后序遍历序列相同的二叉树是只有根的二叉树。 9在信息"ABCD BCD CB DB ACB"中A,B,C,D四个字符出现的频率依次是:2,5,4,3。 在哈夫曼树中每个字符的最优编码: 可得编码为: A-110 B-O C-10 D-II1 信息编码为:110010111 010111 100 1110 110100 10.错误。修改如下: BiTree INSUCC <BiTree x> S=X->rchild;if<s->rtag>while s->ltags=s->lchild;return S; 五、算法设计题1编写对二叉树进行中序遍历的非递归算法,并对算法执行原教材题图6-6所示的二叉树的情况进行跟踪即给出各阶段栈的变化及输出的结点序列。 解答中序遍历的非递归算法如下: void InorderTraverse <BTree T> InitStack <S>p=T;while <p&& 1Empty <S>> if <p> Push<S,p>p=p->lchild; >else pop <S,p>printf< "ooC", p->data>p=p->rchild> 对于给定的二叉树,算法执行情况如下:A入栈,B入栈,D入栈,D出栈,访问D,B出栈,访问B,A出栈,访问A,C入栈,E入栈,E出栈,访问E,G入栈,G出栈,访问G,C出栈,访问C,F入栈,F出栈,访问F,栈和指针p均空,结束。 最后的遍历序列是:DBAGECF。 2假设在表示一棵二叉树的二叉链表上增加两个域:双亲域用于指示其双亲结点,标志域flag可取0,2的值,用以区分在遍历过程中到达该结点时继续向右或向左或访问该结点。试以此存储结构编写不用栈进行后序遍历的递推形式的算法。 解答要解决这一问题必须区分结点在访问过程中的状态,这可通过结点的标志域来处理。对一个结点来说当前的结点可能由:<1>其双亲结点转换;<2>其左子树遍历结束转换; <3>其右予树遍历结束转换。所以,算法主要执行按这三种状态进行处理或处理当前结点或转换结点的状态,从而算法可描述为:void postorder <BTree T> /后序遍历二叉树 /Btree类型的结点含4个域:flag,parent,lchild,rchild; flag初值为0,指针指向根结点 BiTree p=T;while <p>switch <p->flag> case O: p->flag=l; if <p->lchild> p=p->lchild;break;case l: p->flag=2; if <p->rchild> p=p->rchild;break;case 2: p->flag=0; printf <p->data>p=p->parent ; 3.一棵具有n个结点的完全二叉树,以一维数组作为存储结构,试设计一个对该完全二叉树进行前序遍历的算法。 解答设完全二叉树的结点以层次为序,按从上至下,由左至右的顺序编号,存放在一维数组R1,n中。对于编号为t的结点,若存在子结点,其左孩子结点一定是2*t,右孩子结点是2*t+l,由此可得对完全二叉树进行前序遍历的递归算法。 void preorder <int R,int n,int t> /前序遍历二叉树R printf"%Cn",Rt; /输出当前结点值if<t*2<=n>preorder<R,n,t*2> /递归前序遍历左子结点if<t*2+1<=n>preorder<R,n,t*2+1> /递归前序遍历右子结点 4在不使用栈和递归的条件下,后序序列遍历中序线索二叉树,需要知道任意结点的后序直接后继。中序线索树所能提供的是当前访问结点的祖先双亲信息,利用双亲信息,就可以对中序线索树进行后序遍历。中序线索树有如下性质: 若x是parent的左孩子,则parent是x的最右子孙的右线索。 若x是parent的右孩子,则parent是x的最左子孙的左线索。 因此设计两个函数求给定结点的最左子孙的左线索和最右子孙的右线索;这两个线索均是T的祖先。具体实现如下: typedef enumLink, Thread Pointer Tag; /Link=0:指针;Thread=l:线索 typedef struct BiThrNode /中序线索树结点结构ElemrType dataStruct BiThrHode lchild, rchild;PointerTag ltag, Rtag; BiThrNode, *BiThrNode;typedef enum lEFT, RIGHT> TagType;BiTHrNode *LeftMose< BiTHrTree T> /求T的最左子孙的左线索 BighrNode *p=T;while <p->Ltag! =Thread> p-p->lchild;if <p->lchild> return p->lchild;else return NULL;BiTHrNode *RightMost <BiTHrTree T> /求T的最右子孙的右线索 BiThrNode *p=T;while <p->Rtag!=Thread> p-p->rchild;if <p->rchild> return p->rchild;else return NULL; int Isrightchild <BiThrTree T,BiThrTree &parent>/判断T是否是parent的右孩子,若是返回1,否则返回O parent=LeftMost<T>if <parentparent->rchild=p> return l;else <parent=NUIL; return O;> void posttraverseInThrTree <BiTheTree T>/后序遍历中序线索树,当访问标志tag为RIGHT时才访问当前结点Tagtype tag; /待访问标志,表示当前结点是从左孩子还是右孩子返回的while <p> while <p->ltag!=Thread> p=p->lchild;if <p->rtag=link> tag=LEFT;/左孩子为线索,右孩子为链,相当于从左返回else tag=RIGHT;/当前结点为叶结点,相当于从右返回while< tag=RiGHT> visit <p> /仅当tag=RIGHT时返回if <Isrightchild <p, parent>/从右孩子返回,需访问parent,修改p指向双亲 p=parent; tag=RIGHT;>else/p是左孩子,用最右的线索找双亲结点 p=RightMost <p>if <pp->Rtag=Thread> tag=RIGHT;else tag=LEFT;if <tag=LEFT&p> p=p->rchild; 5凹入表示法打印二叉树: 采用前序遍历的递归函数依次输出各结点的值,子结点比父结点右缩进3个字符宽度,具体实现算法如下: Void disp <BiTree T, int space> /space为空格数 int i;if <t> for <i=l; i<space; i+> printf<" "> /输出space个空格printf<"%dn¨, p->data>disp <T->lchild, space+3>disp <T->rchild, space+3> 6前序遍历一棵中序线索树: 在不使用栈和递归的情况下对线索二叉树进行前序遍历,需要知道任意结点前序的直接后继。 typedef enumf Link,Thread>PointerTag; /Link:0指针,Thread:1线索 typedef struct BiThrNodet /中序线索树结点结构ElemType data;Struct BiThrNode lchild, rchild;PointerTag Ltag, Rtag; BiThrNode, *BiThrTree ; void pretraversethread<BiThrTree T> /前序遍历带头结点的中序线索树T BiTrhTree p=T->lchild;while<p!=T> while <p->Ltag=Link> /遍历到最左端 visit <p> p=p->lchild;>visit <p> /访问最左端结点,然后向右转while <p->Rtag=Thread> /由右线索向上p=p- >rchild;if <p->Rtag=link> /右链域为指针,则转右于树,继续右于树前序遍历p=p->rchild; 算法时间复杂度为O<n>。 7以二叉链表为存储结构,写出交换各结点左右子树的算法。 解答要交换各结点的左右子树,最方便的办法是用后序遍历算法,每访问一个结点时把两棵子树的指针进行交换,最后一次访问是交换根结点的子树。算法如下: typedef char DataType; /定义DaTaType类型 typedef struct node DataType data; struct node lchild,rchild; /左右孩子子树 BinNode; /结点类型 typedef BinNode *BinTree; #include<stdioH> void ChangeBinTee <BinTree *T> /交换子树 if<*T> /这里以指针为参数使交换在实参的结点上进行BinTreetemp; /后序遍历ChangeBinTree<<*T> ->lchild>ChangeBinTree<<*T> ->rchlld>temp= <*T> ->lchild;<*T> ->lchild= <*T> ->rchild;<*T> ->rchild=temp; void PrintNode <BinTree T> /以前序序列打印结点数据 if <T>Printf<¨%C", T->data>PrintNode <T->lchild>PrintNode< T->rchiid> void main<> /测试程序 BinTree root;CreatBinTree< &root> /建立二叉链表PrintNode <root> /输出原表printf< "n">ChangeBinTree< &root> /交换子树PrintNode <root> /输出新表printf<"n"> 16 / 16