数据结构

数据结构,第1张

目录

第5章  树和二叉树


一、选择题


二、应用题

(1)试找出满足下列条件的二叉树

(2)设一棵二叉树的先序序列: A B D F C E G H ,中序序列: B F D A G E H C

  (3) 假设用于通信的电文仅由8个字母组成,字母在电文中出现的频率分别为0.07,0.19,0.02,0.06,0.32,0.03,0.21,0.10。


 (4)已知下列字符A、B、C、D、E、F、G的权值分别为3、12、7、4、2、8,11,试填写出其对应哈夫曼树HT的存储结构的初态和终态。



三、算法设计题

以二叉链表作为二叉树的存储结构,编写以下算法:

(1)统计二叉树的叶结点个数。


(2)判别两棵树是否相等。


(3)交换二叉树每个结点的左孩子和右孩子。


(4)设计二叉树的双序遍历算法(双序遍历是指对于二叉树的每一个结点来说,先访问这个结点,再按双序遍历它的左子树,然后再一次访问这个结点,接下来按双序遍历它的右子树)。


(5)计算二叉树最大的宽度(二叉树的最大宽度是指二叉树所有层中结点个数的最大值)。


(6)用按层次顺序遍历二叉树的方法,统计树中具有度为1的结点数目。


(7)求任意二叉树中第一条最长的路径长度,并输出此路径上各结点的值。


(8)输出二叉树中从每个叶子结点到根结点的路径。


第5章  树和二叉树

一、选择题

(1)把一棵树转换为二叉树后,这棵二叉树的形态是(   )。


             

A.唯一的                          B.有多种

C.有多种,但根结点都没有左孩子    D.有多种,但根结点都没有右孩子

(2)由3 个结点可以构造出多少种不同的二叉树?(    )

A.2          B.3             C.4          D.5   

(3)一棵完全二叉树上有1001个结点,其中叶子结点的个数是(  )


A.250         B. 500          C.254        D.501   

(4)一个具有1025个结点的二叉树的高h为(  )


A.11          B.10             C.11至1025之间       D.10至1024之间

(5)深度为h的满m叉树的第k层有(  )个结点。


(1=

A.mk-1          B.mk-1            C.mh-1        D.mh-1

(6)利用二叉链表存储树,则根结点的右指针是(  )


A.指向最左孩子        B.指向最右孩子         C.空        D.非空

(7)对二叉树的结点从1开始进行连续编号,要求每个结点的编号大于其左、右孩子的编号,同一结点的左右孩子中,其左孩子的编号小于其右孩子的编号,可采用(  )遍历实现编号。


A.先序         B. 中序           C. 后序       D. 从根开始按层次遍历

(8)若二叉树采用二叉链表存储结构,要交换其所有分支结点左、右子树的位置,利用(  )遍历方法最合适。


A.前序         B.中序            C.后序      D.按层次

(9)在下列存储形式中,(  )不是树的存储形式?

A.双亲表示法   B.孩子链表表示法   C.孩子兄弟表示法   D.顺序存储表示法

(10)一棵非空的二叉树的先序遍历序列与后序遍历序列正好相反,则该二叉树一定满足(  )


A.所有的结点均无左孩子        B.所有的结点均无右孩子

C.只有一个叶子结点            D.是任意一棵二叉树

(11)某二叉树的前序序列和后序序列正好相反,则该二叉树一定是(  )的二叉树。


A.空或只有一个结点            B.任一结点无左子树  

C.高度等于其结点数            D.任一结点无右子树

(12)若X是二叉中序线索树中一个有左孩子的结点,且X不为根,则X的前驱为(  )


A.X的双亲                      B.X的右子树中最左的结点

CX的左子树中最右结点          D.X的左子树中最右叶结点

(13)引入二叉线索树的目的是(  )


A.加快查找结点的前驱或后继的速度    B.为了能在二叉树中方便的进行插入与删除

C.为了能方便的找到双亲              D.使二叉树的遍历结果唯一

(14)线索二叉树是一种(  )结构。


A.逻辑         B. 逻辑和存储          C.物理            D.线性

(15)设F是一个森林,B是由F变换得的二叉树。


若F中有n个非终端结点,则B中右指针域为空的结点有(  )个。


A. n-1          B.n                    C. n+1           D. n+2


二、应用题 1试找出满足下列条件的二叉树

① 先序序列与后序序列相同    ②中序序列与后序序列相同

③ 先序序列与中序序列相同    ④中序序列与层次遍历序列相同

先序遍历二叉树的顺序是“根—左子树—右子树”,中序遍历“左子树—根—右子树”,后序遍历顺序是:“左子树—右子树―根",根据以上原则,本题解答如下:

(1)  若先序序列与后序序列相同,则或为空树,或为只有根结点的二叉树

(2)  若中序序列与后序序列相同,则或为空树,或为任一结点至多只有左子树的二叉树.

(3)  若先序序列与中序序列相同,则或为空树,或为任一结点至多只有右子树的二叉树.

(4)  若中序序列与层次遍历序列相同,则或为空树,或为任一结点至多只有右子树的二叉树

2设一棵二叉树的先序序列: A B D F C E G H ,中序序列: B F D A G E H C

①画出这棵二叉树。


②画出这棵二叉树的后序线索树。


③将这棵二叉树转换成对应的树(或森林)

  

  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 

 

 方案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

结论:哈夫曼编码优于等长二进制编码

字母编号

对应编码

出现频率

1

1100

0.07

2

00

0.19

3

11110

0.02

4

1110

0.06

5

10

0.32

6

11111

0.03

7

01

0.21

8

1101

0.10

(100)

(40)      (60)

19     21     32   (28)

  1. (11)

   7     10  6    (5)

                 2     3


方案比较:

字母编号

对应编码

出现频率

1

000

0.07

2

001

0.19

3

010

0.02

4

011

0.06

5

100

0.32

6

101

0.03

7

110

0.21

8

111

0.10

方案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

0

0

0

2

12

0

0

0

3

7

0

0

0

4

4

0

0

0

5

2

0

0

0

6

8

0

0

0

7

11

0

0

0

8

0

0

0

9

0

0

0

10

0

0

0

11

0

0

0

12

0

0

0

13

0

0

0

终态

weight

parent

lchild

rchild

1

3

8

0

0

2

12

12

0

0

3

7

10

0

0

4

4

9

0

0

5

2

8

0

0

6

8

10

0

0

7

11

11

0

0

8

5

9

5

1

9

9

11

4

8

10

15

12

3

6

11

20

13

9

7

12

27

13

2

10

13

47

0

11

12


三、算法设计题 以二叉链表作为二叉树的存储结构,编写以下算法: 1统计二叉树的叶结点个数。


int LeafNodeCount(BiTree T)

{

if(T==NULL)

return 0;                                //如果是空树,则叶子结点个数为0

else if(T->lchild==NULL&&T->rchild==NULL)

return 1;                                //判断该结点是否是叶子结点(左孩子右孩子都为空),若是则返回1

else

return LeafNodeCount(T->lchild)+LeafNodeCount(T->rchild);

}

2判别两棵树是否相等。


3交换二叉树每个结点的左孩子和右孩子。


void ChangeLR(BiTree &T)

{

BiTree temp;

if(T->lchild==NULL&&T->rchild==NULL)

return;

else

{

temp = T->lchild;

T->lchild = T->rchild;

T->rchild = temp;

}

ChangeLR(T->lchild);

ChangeLR(T->rchild);

}

4设计二叉树的双序遍历算法(双序遍历是指对于二叉树的每一个结点来说,先访问这个结点,再按双序遍历它的左子树,然后再一次访问这个结点,接下来按双序遍历它的右子树)。


void DoubleTraverse(BiTree T)

{

if(T == NULL)

return;

else if(T->lchild==NULL&&T->rchild==NULL)

cout<data;

else

{

cout<data;

DoubleTraverse(T->lchild);

cout<data;

DoubleTraverse(T->rchild);

}

}

5计算二叉树最大的宽度(二叉树的最大宽度是指二叉树所有层中结点个数的最大值)。


[题目分析] 求二叉树高度的算法见上题。


求最大宽度可采用层次遍历的方法,记下各层结点数,每层遍历完毕,若结点数大于原先最大宽度,则修改最大宽度。


int Width(BiTree bt)//求二叉树bt的最大宽度

{if (bt==null) return (0);  //空二叉树宽度为0

else 

{BiTree Q[];//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->lchild;   //左子女入队

if (p->rchild!=null)  Q[++rear]=p->rchild;   //右子女入队

   if (front>last)      //一层结束,

    {last=rear;

if(temp>maxw) maxw=temp;//last指向下层最右元素, 更新当前最大宽度

     temp=0;

 }//if    

}//while

  return (maxw);

}//结束width

6用按层次顺序遍历二叉树的方法,统计树中具有度为1的结点数目。


int Level(BiTree bt) //层次遍历二叉树,并统计度为1的结点的个数

{int num=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->lchild && p->rchild)num++;//度为1的结点

if(p->lchild) QueueIn(Q,p->lchild); //非空左子女入队

if(p->rchild) QueueIn(Q,p->rchild); //非空右子女入队

}  }//if(bt)         

return(num); }//返回度为1的结点的个数

7求任意二叉树中第一条最长的路径长度,并输出此路径上各结点的值。


[题目分析]因为后序遍历栈中保留当前结点的祖先的信息,用一变量保存栈的最高栈顶指针,每当退栈时,栈顶指针高于保存最高栈顶指针的值时,则将该栈倒入辅助栈中,辅助栈始终保存最长路径长度上的结点,直至后序遍历完毕,则辅助栈中内容即为所求。


void LongestPath(BiTree bt)//求二叉树中的第一条最长路径长度

{BiTree p=bt,l[],s[]; //l, s是栈,元素是二叉树结点指针,l中保留当前最长路径中的结点

  int i,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 && !s[top]->Rc)  //只有到叶子结点时,才查看路径长度

if(top>longest) {for(i=1;i<=top;i++) l[i]=s[i]; longest=top; top--;}

//保留当前最长路径到l栈,记住最高栈顶指针,退栈

}

     else if(top>0) {tag[top]=1; p=s[top].Rc;}   //沿右子分枝向下

   }//while(p!=null||top>0)

}//结束LongestPath

8输出二叉树中从每个叶子结点到根结点的路径。


[题目分析]采用先序遍历的递归方法,当找到叶子结点*b时,由于*b叶子结点尚未添加到path中,因此在输出路径时还需输出b->data值。


对应的递归算法如下:

void AllPath(BTNode *b,ElemType path[],int pathlen)

{

    int i;

    if (b!=NULL)

    {

        if (b->lchild==NULL && b->rchild==NULL) //*b为叶子结点

        {

            cout << " " << b->data << "到根结点路径:" << b->data;

            for (i=pathlen-1;i>=0;i--)

        cout << endl;

    }

    else

    {

        path[pathlen]=b->data;           //将当前结点放入路径中

        pathlen++;                       //路径长度增1

        AllPath(b->lchild,path,pathlen); //递归扫描左子树

        AllPath(b->rchild,path,pathlen); //递归扫描右子树

        pathlen--;                       //恢复环境

    }

  }

}

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/607575.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-14
下一篇 2022-04-14

发表评论

登录后才能评论

评论列表(0条)

保存