树
(1)相关概念
兄弟节点:节点的父节点是同一个节点,所以它们之间互称为兄弟节点。
根节点:没有父节点的节点叫作根节点
叶子节点:没有子节点的节点叫作叶子节点或者叶节点。
节点的高度:节点到叶子节点的最长路径(边数)。
节点的深度:根节点到这个节点所经历的边的个数。
节点的层数:节点的深度 + 1.
树的高度:根节点的高度。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G7MY1WWx-1585234305704)(C:\Users\lin\AppData\Roaming\Typora\typora-user-images\1585227146916.png)]](https://i-blog.csdnimg.cn/blog_migrate/d79b6b06a60239a436aef3ff2407b30d.png)
记这几个概念,还有一个小窍门,就是类比“高度”、“深度”、“层”这几个名词在生活中的含义。
在生活中,“高度”这个概念,其实就是从下往上度量,比如要度量第 10 层楼的高度、第 13 层楼的高度,起点都是地面。所以,树这种数据结构的高度也是一样,从最底层开始计数,并且计数的起点是 0。
“深度”这个概念在生活中是从上往下度量的,比如水中鱼的深度,是从水平面开始度量的。所以,树这种数据结构的深度也是类似的,从根结点开始度量,并且计数起点也是 0。
“层数”跟深度的计算类似,不过,计数起点是 1,也就是说根节点的位于第 1 层。
(2)二叉树(Binary Tree)
二叉树,顾名思义,每个节点最多有两个“叉”,也就是两个子节点,分别是左子节点和右子节点。不过,二叉树并不要求每个节点都有两个子节点,有的节点只有左子节点,有的节点只有右子节点。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lvvxBsdg-1585234305711)(C:\Users\lin\AppData\Roaming\Typora\typora-user-images\1585228609837.png)]](https://i-blog.csdnimg.cn/blog_migrate/594f118f9997183fa7f06acddf63528e.png)
编号 2 的二叉树中,叶子节点全都在最底层,除了叶子节点之外,每个节点都有左右两个子节点,这种二叉树就叫作满二叉树。
编号 3 的二叉树中,叶子节点都在最底下两层,最后一层的叶子节点都靠左排列,并且除了最后一层,其他层的节点个数都要达到最大,这种二叉树叫作完全二叉树。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-10nrulvD-1585234305731)(C:\Users\lin\AppData\Roaming\Typora\typora-user-images\1585228784320.png)]](https://i-blog.csdnimg.cn/blog_migrate/fb0e8cb61a82ae0961ea2345d692bc8a.png)
存储一棵二叉树,我们有两种方法,一种是基于指针或者引用的二叉链式存储法,一种是基于数组的顺序存储法。
1. 链式存储法
每个节点有三个字段,其中一个存储数据,另外两个是指向左右子节点的指针。
只要拎住根节点,就可以通过左右子节点的指针,把整棵树都串起来。这种存储方式我们比较常用。大部分二叉树代码都是通过这种结构来实现的。

2. 顺序存储法
把根节点存储在下标 i = 1 的位置,那左子节点存储在下标 2 * i = 2 的位置,右子节点存储在 2 * i + 1 = 3 的位置。以此类推,B 节点的左子节点存储在 2 * i = 2 * 2 = 4 的位置,右子节点存储在 2 * i + 1 = 2 * 2 + 1 = 5 的位置。
如果节点 X 存储在数组中下标为 i 的位置,下标为 2 * i 的位置存储的就是左子节点,下标为 2 * i + 1 的位置存储的就是右子节点。反过来,下标为 i/2 的位置存储就是它的父节点。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S9tbQpEM-1585234305739)(C:\Users\lin\AppData\Roaming\Typora\typora-user-images\1585229609566.png)]](https://i-blog.csdnimg.cn/blog_migrate/91d00085c9104d7085f88543b0727277.png)
不过,上面的例子是一棵完全二叉树,所以仅仅“浪费”了一个下标为 0 的存储位置。如果是非完全二叉树,其实会浪费比较多的数组存储空间。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yKrpZ94D-1585234305742)(C:\Users\lin\AppData\Roaming\Typora\typora-user-images\1585229773296.png)]](https://i-blog.csdnimg.cn/blog_migrate/8b0e3415ad4ce1fef354e3e0e7e69efd.png)
所以,如果某棵二叉树是一棵完全二叉树,那用数组存储无疑是最节省内存的一种方式。因为数组的存储方式并不需要像链式存储法那样,要存储额外的左右子节点的指针。这也是为什么完全二叉树会单独拎出来的原因,也是为什么完全二叉树要求最后一层的子节点都靠左的原因。
3. 二叉树的遍历
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l4xZpmmi-1585234305747)(C:\Users\lin\AppData\Roaming\Typora\typora-user-images\1585232103561.png)]](https://i-blog.csdnimg.cn/blog_migrate/45db11d82d78f2a6e5fb1794e186aea0.png)
经典的方法有三种,前序遍历、中序遍历和后序遍历。
-
前序遍历是指,对于树中的任意节点来说,先打印这个节点,然后再打印它的左子树,最后打印它的右子树。
preOrderTraverse(callback) { const preOrderTraverseNode = (node, callback) => { if (node !== null) { callback(node.key) preOrderTraverseNode(node.left, callback) preOrderTraverseNode(node.right, callback) } } preOrderTraverseNode(this.root, callback) } tree.inOrderTraverse(value => { console.log(value) })<

本文介绍了树的相关概念,包括节点的深度、高度和层数。接着详细讲解了二叉树,特别是链式存储法和顺序存储法,以及二叉树的遍历。然后深入探讨了二叉查找树(Binary Search Tree),包括查找、插入和删除操作,以及在不同形态下的时间复杂度分析。最后,对比了二叉查找树相对于散列表的优势。
最低0.47元/天 解锁文章
1743

被折叠的 条评论
为什么被折叠?



