![00a630f3aac0e81ca41e9b3c7d2a0a02.png](https://i-blog.csdnimg.cn/blog_migrate/d7f7a0f45e51b58229492f0468136aed.jpeg)
本篇使用JS继续实现二叉树的一些操作,名字里有高级,其实和《JavaScript高级程序设计》的名字里也有高级但是其实整本书都是很基础的知识一样,本篇的操作说到底也是很基础的操作。
首先通过代码框架来看看本篇都会设计到哪些操作。
代码框架
class
获得二叉树中节点个数
获取二叉树中的节点个数可以有递归和非递归两种方法,递归的方法思路比较简单,根节点加上左子树节点的个数,加上右子树节点的个数返回就行了。非递归的方法就使用到了上一篇提到的二叉树中比较重要的层次遍历操作,只要在每次节点出队的时候计数加一就行了。
对应的代码如下:
getNodeNumber
而要是使用递归来实现的话,代码就会变得异常的简洁:
getNodeNumber
使用祖传的二叉树来测试下算法的正确性:
![0f0765dac47a4be1397ee129df769378.png](https://i-blog.csdnimg.cn/blog_migrate/bb8bac56332b20b9d9f6e7c322244bfb.jpeg)
为了节省篇幅,关于这棵二叉树的建立方法就不列出来了,可以参考这个系列的第一篇文章。
console
无论使用上述两种方法的那一种,结果都是相同的。
叶子节点的个数
同样,统计叶子节点的个数也用到了层次遍历。和统计节点个数的不同之处只是在于只有出队列的节点同时没有左右子树时,计数才加一
对应的代码如下:
getLeafNodeNumber
同样提供下非递归的版本,在当前节点为空时返回0,为叶子节点时返回1,其他情况再次调用自身。
代码如下:
getLeafNodeNumber
使用图1来测试下:
console
无论使用的是递归还是非递归的代码,得到的都是相同的结果。
二叉树的深度
二叉树的深度指的是从根节点到叶子节点中最长路径的长度为树的深度。根节点的深度为1。
这里使用递归的方法实现,思路是:
- 一颗树只有一个节点,它的深度是1;
- 二叉树的根节点只有左子树而没有右子树,二叉树的深度应该是其左子树的深度加1;
- 二叉树的根节点只有右子树而没有左子树,二叉树的深度应该是其右子树的深度加1;
- 二叉树的根节点既有右子树又有左子树,那么二叉树的深度应该是其左右子树的深度较大值加1。
有了思路之后,再去实现代码就很简单了。对应的代码如下所示:
getTreeDepth
使用图1来测试下:
console
给定层数节点的个数
该算法的思路依然是使用层次遍历,具体做法是使用一个变量来保存当前层数节点的个数,用这个变量作为内层循环结束的标识,当内层循环结束时,队列中保存的就是下一层的节点了,这时判断是否等于给定层数,如果相等就直接返回,不相等再进行下一轮循环。
对应的代码如下:
getLevelNodeNumber
使用该代码对图1进行测试:
console
可见是正确的。
判断二叉树是不是完全二叉树
完全二叉树的定义为:
若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。
在判断是不是完全二叉树时,这里提供两种思路,为了区别两种方法,暂时起名为isCompleteTree1和isCompleteTree2。
思路1:补洞法
完全二叉树指的是除了最后一层可能不是满的以外其他层都是满的二叉树,在最后一层在不满的情况下,节点全部分布在左端。因此可以利用这个特征,如果层次遍历时遇到一个空节点后,再向后的遍历的时候依然还有节点,则这个二叉树肯定不是完全二叉树。换言之,只要遍历到一个空节点,其后的节点必须全为空才行。
实现的代码如下:
isCompleteTree1
思路2:如果一个节点只有右子节点,则不是完全二叉树。当遍历到一个不是叶子节点的节点时,如果其前面的节点没有右孩子节点,则不是完全二叉树。
实现的代码如下:
isCompleteTree2
用这个方法测试下图1看看:
console
在7号节点插入左子节点5,在15号节点后插入右子节点16再来试试看
myTree
求二叉树的镜像
所谓的二叉树的镜像指的是:
![651156e181bd8747c0c00fcfae76d2c4.png](https://i-blog.csdnimg.cn/blog_migrate/6dc666f1fb9f740f9f40db2db9cf1c39.png)
看到这个图以后自然就有想法了,不过是将左右子树交换而已嘛,代码如下:
invertTree
用这个方法,来求以下图1的镜像看看:
myTree