数据结构 5-0 树与二叉树总结

前言

数据结构复习过程中最先遭遇的磕碰,这一章内容及其多,而且可以考得很难,不仅是代码题,填空题有些也很有难度。主要是四部分内容:树的基本概念、二叉树、树与森林、树的应用。题目以选择题为主,因为代码题确实手写比较有难度,选择题时画出树的结构是最好的工具。

树的基本概念

许多没什么意思的概念就直接上截图了:
在这里插入图片描述
这里说的是树的定义,里面主要是两个点:除了树根其余所有节点都只有一个前驱,所有节点可以有零个或者多个后继。这个规律在后面计算节点个数的规律时很有用。
在这里插入图片描述
在这里插入图片描述
书上对于概念的叙述很罗嗦,对概念简化一下:图上从A出发走到K,中间经过的点全是K的祖先,反过来称K是A的子孙,K相当于是E产生的,所以E称为K的双亲节点,反过来K是E的孩子结点,K和L都是来自一个双亲节点,所以称为兄弟节点。一个节点有的孩子树就是这个点的度,可以看成下面有几个分支。树里面所有节点最大的度就是树的度。没有孩子节点的节点称为叶节点,不是叶节点就称为分支节点(在树中间部分)。深度和高度注意好方向即可。森林是许多棵树的集合,比较极端的情况是整个森林是由许多个节点组成的森林,但仍然符合定义,因为只有根节点也可以算作一棵树。

在概念部分,最重要的是树的性质,树具有如下的基本性质:
①节点数等于所有节点的度数加一。所有节点只要有向下的分支,一定产生了一个孩子,反过来理解,除了根节点,所有节点都是由一个节点产生的,所以加一补上根节点。
②度为m的树中第i层上最多有m^(i-1)个节点。节点最多的时候,每层的节点数构成了一个公比为m的等比数列,数列的初值为1,所以根据等比数列的通项公式,第i项即为第i层的节点数。
③高度为h的m叉树至多有(m^h-1)/(m-1)个节点。这条规律也是用等比数列来理解,节点最多的时候,每一层都是满的,所以求此时的节点数相当于求等比数列的前h项和,利用公式直接写出这条规律。
④具有n个节点的m叉树最小高度为在这里插入图片描述
这条规律解释起来稍微有点麻烦,规律说的是最小高度,所以说树的上面部分一定是排满的,如果树有h层,那么前h-1层一定是排满的,此时就可以逆用规律③,得到下面的等式,而此时的h不一定是整数,采用向上取整的方法来让其变为整数,向上取整也是结合了树的层数的计数规律,这一点不难发现。
在这里插入图片描述

二叉树

二叉树是树里面比较有代表性的,分支数太多会让树的结构太臃肿,两个分支不仅保证了树在简洁的同时还存储了足够的数据,而且还可以与01二进制结合,所以是最常用的树。二叉树本质上还是一棵树,所以树的概念在这里依然适用。

在二叉树的概念这里出现了第一个比较容易混的点:二叉树与度为2的有序树的区别。首先二叉树是有序树,其交换左右子树一定会导致二叉树变成另一棵树。但是二叉树的节点的度不一定都是2,二叉树可以只有一个子树甚至没有都可以,但度为2的有序树却不能,后者至少要有三个节点,而且这三个节点必须能让树的度为2才行,此外度为2的有序树的左右次序是相对于另一个孩子而言的,如果只有一个孩子那也就没有顺序可言了。
在这里插入图片描述
在二叉树中,又给一些常见形态的二叉树起了别名:
①满二叉树:高度为h且含有2^h-1个节点的树称为满二叉树。就是在上一部分中说到的排满的树。满二叉树中每一层都是满的,即除了叶子节点每个节点都有两个孩子。如果按照从上到下从左到右的顺序给树中的每个节点编号,那么编号为i的节点,除以二就是其双亲节点,乘以二和乘以二加一就是其两个孩子结点。
②完全二叉树:对于满二叉树的要求过于严苛,每一层必须排满,而多数的二叉树不会排满,所以延伸出完全二叉树,即其每个节点的编号都与满二叉树中的编号一一对应时的二叉树。可以把完全二叉树看做是满二叉树扣去了最下面一层的一部分而形成的树。完全二叉树也是最常考的树之一。其具有如下规律:
在这里插入图片描述
其中需要解释一下,第二条叶子节点出现在两层,是因为完全二叉树不一定排满,所以在倒数第二层上可能出现叶子节点,而且只能是出现在右边,相对的最下面一层的叶子节点只能出现在左边。
③二叉排序树:根据输入数据的大小进行动态调整的树,这种树会在树的应用上总结。
④平衡二叉树:最麻烦的一种树,是指任一节点的左右子树的深度之差不超过1的二叉排序树,这种树也会在树的应用中总结。

二叉树的性质常在选择题里面考察,考得很灵活,主要有下面的性质:
在这里插入图片描述
其中,第一条的性质的推导过程一定要灵活使用,这条规律不仅会用在二叉树,在计算节点数目的题中也会经常用到。其余规律都是树的规律在二叉树中的具体化。

二叉树的代码实现可以参考之前第二节的总结
https://blog.csdn.net/weixin_43849505/article/details/107323532
总的来说,一般二叉树用链式存储而不用顺序存储,因为顺序存储必须要解决空间的浪费问题,链式存储灵活分配的特点刚好适合二叉树的需求。

二叉树的遍历与线索化

这一部分是代码题的集中部分,在这里考代码题,代码手写有难度但不至于彻底写不出来。
遍历递归:https://blog.csdn.net/weixin_43849505/article/details/107371412
遍历非递归:https://blog.csdn.net/weixin_43849505/article/details/107371757
线索化:https://blog.csdn.net/weixin_43849505/article/details/107396769
遍历分为四种:前序、中序、后序和层序,前三者区别在于访问节点顺序和子树顺序的先后,层序算是一种例外,一层一层借助队列来访问。具体的代码在之前的小节里面都有,这里就不再赘述了。

遍历这里常考的题就是根据遍历序列构建二叉树。由先序和中序时可以唯一确定一棵二叉树的,后序序列和中序序列也可以唯一确定,其余组合是确定不出来的。对于选择填空题,只要按照两个序列画就完事了,先序遍历的第一个节点和后序遍历的最后一个节点一定是二叉树的根节点,根据这个,将中序遍历划分为两部分,再对两部分做同样的操作,理解了这个过程并不难做。
在这里插入图片描述
线索化的知识在前面的小节里面也有。总的来说,线索二叉树是普通二叉树的一种改进,优化了普通二叉树只能表示父子关系而在前驱后继的方面上比较麻烦的特点,通过人为规定前驱后继指针,来加快查找前驱后继节点的速度。选择题最好将树的指向情况都在树里面标注下,这样更方便去找前驱后继。

树与森林

二叉树是树中的一个特例,对于一般的树,还有别的考察点。
不同于一般的二叉树,树具有三种表示方法:双亲表示法、孩子表示法、孩子兄弟表示法。
双亲表示法最好理解,把二叉树里面的指针方向反过来就行了,让指针从孩子指向双亲,这样的好处是方便找双亲,但是缺点也很明显-不方便找孩子。一般使用这种表示法多用顺序存储,最好的实例就是并查集:https://blog.csdn.net/weixin_43849505/article/details/107499141。
在这里插入图片描述

孩子表示法是将每个节点的孩子节点都用单链表连接起来形成一个线性结构,用孩子链表来表示,叶节点的孩子链表为空,这种操作方式方便找孩子,但是找双亲节点却又麻烦的要死。从图不难看出,一个孩子链表中的节点在树中实际都是兄弟节点。在这里插入图片描述
孩子兄弟表示法,也称二叉树表示法,是综合了上面两种方法得到的表示方法,它规定让左指针指向第一个孩子,右指针指向下一个兄弟,以此来构建二叉树,这样可以把一颗树转换为与之对应的二叉树。易于查找孩子,但是找双亲节点依然有困难,可以补一个指针指向其双亲节点来弥补这个问题。

这三类表示方法之后,就可以让一颗树转换为二叉树,转换规则为:让每个节点左指针指向第一个孩子,右指针指向下一个兄弟。由于根节点没有兄弟,所以转换后一定没有右子树。具体操作时,先在所有兄弟之间加一条横向连线,之后对每个节点,只保留与第一个孩子的连线,之后以树根为轴,调整整棵树的方向,让其符合二叉树的方向习惯。
在这里插入图片描述

如果要把森林转换为二叉树,其操作与树转二叉树类似。先把森林中的每棵树都转换为二叉树,之后从第一棵树开始,把下一棵树看做当前树的兄弟节点,以此再把所有转换好的二叉树连接起来。如果需要将二叉树再转换为森林,只需要从根节点开始,把根节点和其左子树摘出来,一直重复直到整棵二叉树完全拆完,得到的就是森林里面所有树的二叉树状态。
在这里插入图片描述
二叉树中的三种遍历方式,对应到树和森林中,换为先根遍历、后根遍历、层次遍历,思路与二叉树遍历一致,这里就不做赘述了。森林转换为二叉树时,第一棵子树森林转换为左子树,剩余树的森林转换为了右子树,所以森林的先序和中序遍历即为对应二叉树的先序和中序遍历。

树与二叉树的应用

应用这里涉及的知识点很多而且很难,陈越版本的数据结构和严蔚敏版的提到的知识也不一样。

一、二叉排序树
二叉排序树可以看作是动态生成的一颗二叉树,一般来说二叉树只有节点上的限制,而对存放在其内部的数据没有限制,二叉排序树则是规定,左子树的值要小于节点的值,右子树的值要大于节点的值,做了如此规定,不难发现对二叉排序树做中序遍历得到的一定是一个递增的有序序列。

二叉排序树的查找,通过比较节点值和要插入数据的值,如果要查找的值小于节点值,就遍历左子树,否则遍历右子树一直寻找直到节点值就是要找的值。代码模板如下:
在这里插入图片描述
二叉排序树的插入是比较重要的点,排序树是一个动态树,树的结构不是一次生成的,而是在查找过程中动态生成的,根据查找的顺序的不同,产生的二叉排序树也是不同的。插入规则为:若原二叉排序树为空,则直接将值作为根节点的值,之后根据目标值与节点值的大小关系,为目标值找到合适的位置再插入树中。代码模板如下:
在这里插入图片描述
在这里插入图片描述

构造二叉排序树的过程实际上就是不断给二叉排序树插入节点的过程,插入节点实际上又是对查找节点的扩展。

对于二叉排序树的删除操作,由于二叉排序树的特殊性,删除节点后不能直接连接,而是应该删除后调整树中节点的关系,保证大小关系不能变。前面两种删除方式还比较好理解,主要是第三种,需要把右子树中序第一孩子结点给提到上面来。
在这里插入图片描述
在这里插入图片描述
二叉排序树的查找效率,主要是取决于树的高度,当二叉排序树为平衡二叉树时,平均查找长度为O(log2n),而当排序树中所有节点都只有左孩子或者只有右孩子时,平均查找长度就成了O(n),平均查找长度的计算方法为节点数乘以高度求和再除以总结点数,查找失败的长度只需要再一般的树上添加一层即可。

二、平衡二叉树
首先,平衡二叉树是一棵二叉排序树,是在二叉排序树的基础上,对平衡因子做限制而确定的树。其中平衡因子是指左右子树的高度差,规定平衡因子只能是0、-1、1中的一个,也可以说平衡因子的绝对值不超过1,简单来说就是左右子树的高度差不超过1.
在这里插入图片描述
要在平衡二叉树中插入节点时,不仅要按照二叉排序树的规定来操作,而且不能破坏排序树的平衡性。如果破坏了平衡性,就需要从最小的子树开始不断调整,使其变得平衡。
在这里插入图片描述

调整为平衡二叉树的过程是最难理解的部分。分为两类四种调整方法。
①LL平衡旋转:指的是在节点A的左孩子的左子树上添加了一个节点使得树变得不平衡了,两个左即为LL。这种情况需要将以A为根节点的子树做一次向右的旋转操作。让A的左孩子B代替A成为子树的根节点,而B原来的右子树变为A的左子树。
在这里插入图片描述
②RR平衡旋转:指的是在节点A的右孩子的右子树上添加了一个节点使得树变得不平衡了,两个右就成了RR。这种情况与LL其实是一样的,让A的右孩子B代替B成为子树的根节点,B原来的左子树变为A的右子树。LL和RR实际上是两个正好相对的。其操作是镜像的,所以可以归为一类。这一类操作比较简单,也很好去理解。
在这里插入图片描述

也可以用另一种方式去理解,LL是因为左子树更重而不平衡的,就相当于拿一个称去量这个子树,一开始A挂在秤杆上,左边重,应该让它的左边的节点挂到称上,于是用B代替A挂在秤杆上,向上一提就成了B为根节点的子树,但是这个时候B下面连了三个孩子,超生了,所以要用二叉排序树的规则给它重新调整,根据大小关系智能吧B原来的右子树移动到A的左子树上。两种方式实际上是一样的,只不过理解的角度不同。

③LR平衡旋转:也称LR双旋,是指在A的左孩子的右子树上加了一个节点导致树的平衡性被破坏了。此时需要进行两次旋转来保证平衡性。先对A的左子树做一次RR单旋,虽然左子树的平衡性没有被破坏,但为了A的平衡性,这一步是必须的。做完RR单旋之后,再对A节点做一次LL单旋,最后调整出来的树就是平衡的。
在这里插入图片描述
④RL平衡旋转:也称RL双旋,是指在A的右孩子的左子树上加了一个节点导致树的平衡性被破坏了。
不难看出这个情况和LR正好是对应的,所以这两个情况可以分为一类。平衡的方法和LR类似,只不过换为先做一次LL单旋再做一次RR单旋。
在这里插入图片描述
四种平衡旋转,其实可以分为两类,前两种情况只需要一次单旋即可,而后两种情况则需要两次单旋,所以从的来说调整都是以单旋为基础调整的。

除此之外,平衡二叉树在节点数目上有这样的规律:用ni表示深度为i的平衡树含有的最少节点,显然n0=0,n1=1,n2=2,后面根据递归的定义,不难得出ni=(ni-1)+(ni-2)+1。

三、哈夫曼树和哈夫曼编码
哈夫曼树本身是为了解决带权路径的问题而出现的树,在很多情况下,树中的节点都被带上一个含义,记为节点的权,到任意节点的路径长度与节点权的乘积的和为树的带权路径长度,根据建树的方式不同,得到的树的带权路径长度也是不一样的,其中带权路径长度最小的就称为哈夫曼树,也称最优二叉树,直观上看,哈夫曼树中权重大的节点一般放在靠上的位置,权值小的一般放在下面的位置。

构造哈夫曼树的过程也很简单,将所有带权结点拿出来,全部当做只有一个节点的树,每次选取权值最小的两个树进行合并,合并后的节点的权值为左右子树权值之和,合并后再次加入森林,重复这个操作直到所有的树合并为了一个树。
在这里插入图片描述
不难看出,这样做可以使权重高的节点路径长度短,从而使得整体的路径长度就小。

在数据通信中,若对每个字符用相等长度的二进制位表示,称这种编码方式为固定长度编码。 若允许对不同字街用不等长的二进制位表示,则这种编码方式称为可变长度编码。 可变长度编码 比固定长度编码要好得多, 其特点是对频率高的字符赋以短编码,而对频率较低的字符则赋以较 长一些的编码,从而可以使字符的平均编码长度减短,起到压缩数据的效果。 哈夫曼编码是一种被广泛应用而且非常有效的数据压缩编码。

若没有一个编码是另一个编码的前缀,则称这样的编码为前缀编码。最直观的特点就是没有重复前缀,根据一个前缀可以唯一确定一个编码。利用哈夫曼树,向左为0向右为1,可以写出里面各个节点的哈夫曼编码,不难看出,这种方式得到的编码正好是前缀编码,这是因为用遍历二叉树的角度去看,编码里面的01实际上就是指示了走到一个节点的方法,而一棵树不可能会用一种方法走到同一个节点。哈夫曼树本身又是带权路径最小的,所以得到的编码理论上也是很优的。

其实左右谁为0谁为1并没有明确的规定,一般根据题目要求来定,没有明说的话就按照左0右1的方式去找。

四、大顶堆小顶堆
这部分在严蔚敏版本的数据结构里面没有讲到,陈越版本里面的提到了。学校选的是后者,这里顺便总结一下。

堆对应STL里面的优先队列,堆是一种特殊的队列,取出的元素是按照大小顺序的,其实现一般用二叉树来实现。一般不特指的情况下,堆都是完全二叉树。根据节点值是否大于子节点的值,划分为最小堆和最大堆,当需要从小到大输出时用小顶堆,从大到小则用大顶堆。

最大堆插入时,先按照完全二叉树的插入方法在对应位置上暂时插入,再从新增的最后一个节点的父节点开始,用要插入的元素向下过滤上层节点,当一个节点的值小于新元素的值,就下移这个节点的元素。最大堆删除时,实际上是取出树中最大的元素,即根节点,由于取出后必须保证仍然是最大堆,此时做法是将最后一个元素取出放到根节点的位置,再从根节点向下层过滤,直到调整为最大堆。

建立最大堆时,先根据顺序,建立一棵完全二叉树,之后最后一个有子节点的节点开始,调整为一棵符合最大堆要求的树,调整方法和插入时一样。

错题与典型题

在这里插入图片描述
这种题目就是在考察节点数目与度的推导关系了,二叉树的推导关系只是引子,根本是为了得到任意树的推导关系。把握好节点数等于分支数+1这个关键。对这道题而言,不妨设ni表示度为i的节点的个数,根据节点数等于分支数加一这个规律,得到n=1+n1+2n2+3n3+4n4=n0+n1+n2+n3+n4,将题目中的数据带入,可以得到n0=82,即叶节点个数为82个。不管是几叉树,都按照这个方式去推导。
在这里插入图片描述
根据二叉树的性质,n0=n2+1,总节点数=2n=n0+n1+n2=n1+2n2+1,则n1=2(n-n2)-1,不难看出n1一定为奇数,所以显然选c,c的表达方式说的是有偶数个度为1的节点。
在这里插入图片描述
这两道题放在一起,因为考察的都是同一个问题-二叉树节点个数。题目直说第几层有几个叶节点,但是这并不代表叶节点就只出现在这一层,第六层有八个叶节点,如果是出现在左边,说明是第五层排满了,在排第六层时出现的,而此时第六层的右边是没有节点的,剩余有部分的叶节点在第五层的右边,如果第六层的八个节点出现在这一层的右边,说明是第六层排满了,在第七层的左边排了一部分节点,空着的节点对应到第六层刚好出现了八个叶节点。这两种情况刚好对应了节点最少和最多的两种情况。这种题最好的方法就是画一个简图来表示一下。第十题问的是节点数最少,所以是前五层排满第六层只有8个节点,用节点数公式很快可以写出总节点数为8+2^5-1=39。第十一题问的是节点数最多,所以是前六层排满,第七层右边空着2*8=16个节点,即2^7-1-16=111。
在这里插入图片描述
除了节点数目上的规律,有时也会出题去考节点编号上规律的推导,课本上二叉树的推导都是引子,以此来求任意叉树的规律。
对于这道题来说,第一问节点数目不难求,求节点数目本质上就是求等比数列的前n项和或者求等比数列的某一项,变换叉数就是换公比,所以很容易得到第一问的答案:m^(k-1)。
第二三问求双亲节点和子节点的编号,在m叉树的情况下,节点i的第一个孩子编号为j=(i-1)*m+2,这个式子可以这样去理解,编号为i的节点,它前面一共有i-1个节点,这些节点排满的时候会产生(i-1)*m个分支,这些分支都是指到节点上去的,再加上根节点,这些节点是编号为i的节点的第一个孩子之前的所有节点,再加一就成了第一个孩子的编号。反过来,双亲的编号就成了[(i-2)/m] (向下取整)+1。至于求第k个孩子,也是一样的道理,换成+k即可,即(i-1)*m+1+k。
第四问问的很巧妙,什么时候没有右兄弟,只能是i节点刚好是其双亲节点的最后一个孩子的时候,同理没有左兄弟就是节点是双亲节点的第一个孩子。由于是满m叉树,每一层都是排满的,此时还可以简化为不是双亲节点的第m个孩子就有右兄弟,具体思路如下
在这里插入图片描述

在这里插入图片描述
这道题来说,上来先排除层次遍历,层次的输出结果是一层一层的,必然找不到路径。之后在三种方式里面选择,解释的其实有点牵强,如果是前序或者中序,它会在不知道后面会不会找到n节点的情况下就把m给输出出去,即使后面没有n也会把m的所有子树输出,而后序遍历时,先找到n后找到m,所以找到n后再倒着退回去,就能找到需要的路径了。
在这里插入图片描述
一道很基础的概念题。二叉树是一种逻辑结构,但线索’二叉树是加上线索后的链表结构,即它是二叉树在计算机内 部的一种存储结构,所以是一种物理结构。
在这里插入图片描述
这两道题放在一起,属于同一类型。先序为MLR而后序为LRM,如果下个让这两个刚好相反,即MLR=MRL,必须L和R里面一个是空的,即每层只有一个节点,所以其形态为高度等于节点数。相同则需要MLR=LRM,必须LR都为空,相当于只有一个根节点。
在这里插入图片描述
这道题关键在于如何实现层序遍历,一般直接使用STL里面的队列,很难辨别进行到了哪一层,而使用数组模拟队列可以弥补这个问题,代码里面用last来记录当前一层的最后一个节点所在的位置,以此来记录层的情况。
在这里插入图片描述
当然如果是递归实现就很简单了,直接用递归遍历的模板加一个层数的返回值即可。在这里插入图片描述
在这里插入图片描述
这种题换作选择填空就好做了,按照规律画就行了,用代码实现一开始确实还有点不知道怎么下手,看了答案发现还不是特别难,主要是一个递归的过程。根据先序序列,找出第一个节点作为根节点,将中序遍历的结果划分为两部分,先让左部分递归重复这个过程,之后对右部分递重复这个过程,一直到子树只有一个节点为止。
在这里插入图片描述
在这里插入图片描述
一般的二叉树是做不到这样的交换的,但是由于题目中的是满二叉树,满二叉树左右子树的节点数目相等,而且有先序的第一个节点变成后序的最后一个节点,基于这两个特点,可以实现两种遍历的转换。
主要是一个递归的过程,用l1,h1,l2,h2来标志两段的长度,post记录后序序列,pre记录先序序列。当h1<l1时,什么都不做作为递归结束标志。其余情况下,每次让post[h2]=pre[l1],之后将序列从中间断开,左右子树递归,一直重复到递归结束标志。
在这里插入图片描述

在这里插入图片描述
这个主要考察的还是线索树节点指针的指向问题,后续序列中,如果节点P有右孩子,那么右孩子是其前驱,如果只有左孩子,那么左孩子是其前驱。如果左右孩子都没有,设其中序左线索指向的某祖先节点为f,若f有左孩子,那么左孩子是其后序下的前驱,如果f没有左孩子,则顺其前驱找双亲的双亲,一直找到双亲有左孩子为止。如果p是中序的第一个节点,那么p后序下没有前驱。
在这里插入图片描述

在这里插入图片描述
不得不说,统考题就是比王道自己凑出来的题好多了,至少不会很奇怪。题目就是给树对应的表达式加括号,首先不难发现,对这个二叉树做中序遍历得到的就是没加括号的表达式,可以确定肯定是在中序遍历的基础上做修改,括号刚好加在了一个子树两侧,所以就可以修改递归模板,让左括号加在遍历左子树之前,右括号加在遍历完右子树之后,叶节点不加括号。
在这里插入图片描述
在这里插入图片描述
题目考察的是树转换为二叉树时节点的意义,转换后右指针为空,即没有下一个兄弟,由于是森林转换为的树,当没有下一个树的时候转换后也没有右指针。转换前有n个非终端节点,所以转换后,这n个节点的孩子们必然会有一个孩子没有右指针,所以一共有n+1个节点的右指针为空。

在这里插入图片描述
与上一道题很类似,主要还是理解好森林对应二叉树中没有右孩子的含义,原森林中没有下一个兄弟或者没有下一棵树,或者直接就是对应二叉树中没有右孩子的节点数等于森林中分支数加一。对这道题来说,总节点数减去叶节点数即分支节点数,再加上一就可以得到结果1896.

在这里插入图片描述
直接利用树的规律:n个节点的树有n-1条边,题目里节点数比边数多10,直接就得出有10棵树。没想到题目原来这么简单,拍案叫绝。

在这里插入图片描述
一棵树的先根遍历结果与其对应二叉树的先序遍历结果相同,树的后根遍历结果与其对应二叉树表示的中序遍历结果相同。由于二叉树的先序序列和中序序列能够唯一地确定这棵二叉树, 因此,根据题目给出的条件,利用树的先根遍历序列和后根遍历序列能够唯一地确定这棵树。
在这里插入图片描述
采用递归算法,若树为空,高度为零; 否则, 高度为第一子女树高度加 1和兄弟子树高度的大者。其非递归算法使用队列, 逐层遍历树, 取得树的高度。
在这里插入图片描述

在这里插入图片描述
越来越感觉王道自己出的题头大,用算法实现孩子兄弟链表。其实仔细捋一下,可以从手画孩子兄弟表示法来考虑,可设立一个辅助数组 pointer 存储新建树的各结点的地址, 再根据层次序列与每个结点的度, 逐个t连接结点。
在这里插入图片描述
在这里插入图片描述
这两道题都涉及到了二叉平衡树节点与深度高度的关系,前面提到过二叉平衡树的递推关系,n0=0,n1=1,n2=2,nk=n(k-1)+n(k-2)+1,根据这个递推关系来确定节点数目。两道题都可以用这个递推式来求, 构造 5 层平衡二叉树至少需 12 个结点,构造 6 层至少需要 20 个结点。
在这里插入图片描述
依然用递推公式,所有非叶节点的平衡因子都是1,说明是节点最少的情况,继续用公式推即可。另外答案还附带了其它的两种方法。
在这里插入图片描述
在这里插入图片描述
在哈夫曼编码中,一个编码不能是其他编码的前缀,三位编码可能是 001 ,对应的 4 位编码只能是 0000 和 0001 。 3 位编码也可能是 000,对应的 4 位编码只能是 0010 和 0011。若全采用 4 位编码,则可以 为 0000, 0001,0010 和 0011 。题中问的是最多 ,故选 C。也可以选择用画图的方法,不超过4的哈夫曼编码,对应的哈夫曼树的高度最高就是5,在里面找也可以找出最多四个编码。

在这里插入图片描述
终于出现了哈夫曼树节点的题目了。根据构建哈夫曼树的过程不难发现,度为m的哈夫曼树中只有度为0和m的节点,再用之前二叉树里面常用的节点数目与度的关系可以推知: m*nm = n-1= nm+n0-1 简单处理一下就能找到C

在这里插入图片描述
采用递归的办法,用两个变量来记录左右子树的深度,之后做比较,如果绝对值超过了1就说明不是平衡二叉树。采用后序遍历的方法,如果节点为空,返回高度为0,如果不为空,则返回左右子树最高值加一作为自己这颗子树的高度。
在这里插入图片描述

在这里插入图片描述
统考题就是有点让人摸不到头脑,仔细看题,先合并的表会在后面再次参与合并,如果先合并的表长度长,那么后面比较的次数也就多,这样的规则,正好就是构建哈夫曼树,权值变成了表合并具有的数据元素数目,直接上哈夫曼树的构建模板即可。至于比较次数就是后面排序的知识了。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_43849505/article/details/107568106