|
1 | | -# 数据结构 - 树 |
| 1 | +# 树和二叉树 |
2 | 2 |
|
3 | | -## 一、树的简介 |
| 3 | +## 树 |
| 4 | + |
| 5 | +### 什么是树 |
4 | 6 |
|
5 | 7 | 在计算机科学中,**树**(英语:tree)是一种[抽象数据类型](https://zh.wikipedia.org/wiki/抽象資料型別)(ADT)或是实现这种抽象数据类型的[数据结构](https://zh.wikipedia.org/wiki/資料結構),用来模拟具[有树状结构](https://zh.wikipedia.org/wiki/樹狀結構)性质的数据集合。它是由 n(n>0)个有限节点组成一个具有层次关系的[集合](https://zh.wikipedia.org/wiki/集合)。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。 |
6 | 8 |
|
|
50 | 52 | - [霍夫曼树](https://zh.wikipedia.org/wiki/霍夫曼树):[带权路径](https://zh.wikipedia.org/w/index.php?title=带权路径&action=edit&redlink=1)最短的二叉树称为哈夫曼树或最优二叉树; |
51 | 53 | - [B 树](https://zh.wikipedia.org/wiki/B树):一种对读写操作进行优化的自平衡的二叉查找树,能够保持数据有序,拥有多于两个子树。 |
52 | 54 |
|
53 | | -### 二叉树 |
| 55 | +## 二叉树 |
54 | 56 |
|
55 | | -二叉树是 N 个节点的有限集合,它或者是空树,或者是由一个根节点及两棵不想交的且分别称为左右子树的二叉树所组成。 |
| 57 | +二叉树(Binary Tree)是 N 个节点的有限集合,它或者是空树,或者是由一个根节点及两棵不想交的且分别称为左右子树的二叉树所组成。 |
56 | 58 |
|
57 | | -#### 二叉树的性质 |
| 59 | +### 二叉树的性质 |
58 | 60 |
|
59 | 61 | 1. 二叉树第 i 层上的结点数目最多为 **2<sup>i-1</sup>** (i≥1)。 |
60 | 62 | 2. 深度为 k 的二叉树至多有 **2<sup>k</sup>-1** 个结点(k≥1)。 |
61 | 63 | 3. 包含 n 个结点的二叉树的高度至少为 **log<sub>2</sub>(n+1)**。 |
62 | 64 | 4. 在任意一棵二叉树中,若终端结点的个数为 n0,度为 2 的结点数为 n2,则 n0=n2+1。 |
63 | 65 |
|
64 | | -#### 满二叉树 |
| 66 | +### 满二叉树 |
65 | 67 |
|
66 | 68 | 定义:高度为 h,并且由 **2<sup>h</sup>–1** 个结点的二叉树,被称为满二叉树。 |
67 | 69 |
|
68 | 70 |  |
69 | 71 |
|
70 | | -#### 完全二叉树 |
| 72 | +### 完全二叉树 |
71 | 73 |
|
72 | 74 | 定义:一棵二叉树中,只有最下面两层结点的度可以小于 2,并且最下一层的叶结点集中在靠左的若干位置上。这样的二叉树称为完全二叉树。 |
73 | 75 |
|
74 | 76 | 特点:叶子结点只能出现在最下层和次下层,且最下层的叶子结点集中在树的左部。显然,一棵满二叉树必定是一棵完全二叉树,而完全二叉树未必是满二叉树。 |
75 | 77 |
|
76 | 78 |  |
77 | 79 |
|
78 | | -## 二、算法要点 |
| 80 | +## 二叉查找树 |
| 81 | + |
| 82 | +二叉查找树是二叉树中最常用的一种类型,也叫二叉搜索树。顾名思义,二叉查找树是为了实现快速查找而生的。不过,它不仅仅支持快速查找一个数据,还支持快速插入、删除一个数据。 |
| 83 | + |
| 84 | +**二叉查找树要求,在树中的任意一个节点,其左子树中的每个节点的值,都要小于这个节点的值,而右子树节点的值都大于这个节点的值。** |
| 85 | + |
| 86 | + |
| 87 | + |
| 88 | +### 二叉查找树的查找 |
| 89 | + |
| 90 | +首先,我们看如何在二叉查找树中查找一个节点。我们先取根节点,如果它等于我们要查找的数据,那就返回。如果要查找的数据比根节点的值小,那就在左子树中递归查找;如果要查找的数据比根节点的值大,那就在右子树中递归查找。 |
| 91 | + |
| 92 | + |
| 93 | + |
| 94 | +### 二叉查找树的插入 |
| 95 | + |
| 96 | +如果要插入的数据比节点的数据大,并且节点的右子树为空,就将新数据直接插到右子节点的位置;如果不为空,就再递归遍历右子树,查找插入位置。同理,如果要插入的数据比节点数值小,并且节点的左子树为空,就将新数据插入到左子节点的位置;如果不为空,就再递归遍历左子树,查找插入位置。 |
| 97 | + |
| 98 | + |
| 99 | + |
| 100 | +### 二叉查找树的删除 |
79 | 101 |
|
80 | | -## 三、练习 |
| 102 | +第一种情况是,如果要删除的节点没有子节点,我们只需要直接将父节点中,指向要删除节点的指针置为 null。比如图中的删除节点 55。 |
81 | 103 |
|
82 | | -### 二叉树经典题 |
| 104 | +第二种情况是,如果要删除的节点只有一个子节点(只有左子节点或者右子节点),我们只需要更新父节点中,指向要删除节点的指针,让它指向要删除节点的子节点就可以了。比如图中的删除节点 13。 |
83 | 105 |
|
84 | | -#### 深度优先搜索(DFS) |
| 106 | +第三种情况是,如果要删除的节点有两个子节点,这就比较复杂了。我们需要找到这个节点的右子树中的最小节点,把它替换到要删除的节点上。然后再删除掉这个最小节点,因为最小节点肯定没有左子节点(如果有左子结点,那就不是最小节点了),所以,我们可以应用上面两条规则来删除这个最小节点。比如图中的删除节点 18。 |
85 | 107 |
|
86 | | -在这个策略中,我们采用 深度 作为优先级,以便从跟开始一直到达某个确定的叶子,然后再返回到达另一个分支。深度优先搜索策略又可以根据根节点、左孩子和右孩子的相对顺序被细分为**先序遍历**,**中序遍历**和**后序遍历**。 |
| 108 | + |
87 | 109 |
|
88 | | -- [二叉树的前序遍历](https://leetcode-cn.com/problems/binary-tree-preorder-traversal) |
89 | | -- [二叉树的中序遍历](https://leetcode-cn.com/problems/binary-tree-inorder-traversal) |
90 | | -- [二叉树的后序遍历](https://leetcode-cn.com/problems/binary-tree-postorder-traversal) |
| 110 | +### 二叉查找树的时间复杂度 |
91 | 111 |
|
92 | | -#### 宽度优先搜索(BFS) |
| 112 | +不管操作是插入、删除还是查找,**时间复杂度其实都跟树的高度成正比,也就是 O(logn)**。 |
93 | 113 |
|
94 | | -我们按照高度顺序一层一层的访问整棵树,高层次的节点将会比低层次的节点先被访问到。 |
| 114 | +二叉查找树的形态各式各样。比如这个图中,对于同一组数据,我们构造了三种二叉查找树。它们的查找、插入、删除操作的执行效率都是不一样的。图中第一种二叉查找树,根节点的左右子树极度不平衡,已经退化成了链表,所以查找的时间复杂度就变成了 O(n)。 |
95 | 115 |
|
96 | | -- [二叉树的层序遍历](https://leetcode-cn.com/problems/binary-tree-level-order-traversal) |
| 116 | + |
97 | 117 |
|
98 | | -#### 二叉树和递归 |
| 118 | +### 为什么需要二叉查找树 |
99 | 119 |
|
100 | | -- [二叉树的最大深度](https://leetcode-cn.com/problems/maximum-depth-of-binary-tree) |
101 | | -- [对称二叉树](https://leetcode-cn.com/problems/symmetric-tree) |
102 | | -- [路径总和](https://leetcode-cn.com/problems/path-sum) |
| 120 | +第一,散列表中的数据是无序存储的,如果要输出有序的数据,需要先进行排序。而对于二叉查找树来说,我们只需要中序遍历,就可以在 O(n) 的时间复杂度内,输出有序的数据序列。 |
103 | 121 |
|
104 | | -#### 其他 |
| 122 | +第二,散列表扩容耗时很多,而且当遇到散列冲突时,性能不稳定,尽管二叉查找树的性能不稳定,但是在工程中,我们最常用的平衡二叉查找树的性能非常稳定,时间复杂度稳定在 O(logn)。 |
105 | 123 |
|
106 | | -- [ ] [maximum-depth-of-binary-tree](https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/) |
107 | | -- [ ] [balanced-binary-tree](https://leetcode-cn.com/problems/balanced-binary-tree/) |
108 | | -- [ ] [binary-tree-maximum-path-sum](https://leetcode-cn.com/problems/binary-tree-maximum-path-sum/) |
109 | | -- [ ] [lowest-common-ancestor-of-a-binary-tree](https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/) |
110 | | -- [ ] [binary-tree-level-order-traversal](https://leetcode-cn.com/problems/binary-tree-level-order-traversal/) |
111 | | -- [ ] [binary-tree-level-order-traversal-ii](https://leetcode-cn.com/problems/binary-tree-level-order-traversal-ii/) |
112 | | -- [ ] [binary-tree-zigzag-level-order-traversal](https://leetcode-cn.com/problems/binary-tree-zigzag-level-order-traversal/) |
113 | | -- [ ] [validate-binary-search-tree](https://leetcode-cn.com/problems/validate-binary-search-tree/) |
114 | | -- [ ] [insert-into-a-binary-search-tree](https://leetcode-cn.com/problems/insert-into-a-binary-search-tree/) |
| 124 | +第三,笼统地来说,尽管散列表的查找等操作的时间复杂度是常量级的,但因为哈希冲突的存在,这个常量不一定比 logn 小,所以实际的查找速度可能不一定比 O(logn) 快。加上哈希函数的耗时,也不一定就比平衡二叉查找树的效率高。 |
115 | 125 |
|
116 | | -### 二叉搜索树经典题 |
| 126 | +第四,散列表的构造比二叉查找树要复杂,需要考虑的东西很多。比如散列函数的设计、冲突解决办法、扩容、缩容等。平衡二叉查找树只需要考虑平衡性这一个问题,而且这个问题的解决方案比较成熟、固定。 |
117 | 127 |
|
118 | | -- [ ] [validate-binary-search-tree](https://leetcode-cn.com/problems/validate-binary-search-tree/) |
119 | | -- [ ] [insert-into-a-binary-search-tree](https://leetcode-cn.com/problems/insert-into-a-binary-search-tree/) |
120 | | -- [ ] [delete-node-in-a-bst](https://leetcode-cn.com/problems/delete-node-in-a-bst/) |
121 | | -- [ ] [balanced-binary-tree](https://leetcode-cn.com/problems/balanced-binary-tree/) |
| 128 | +最后,为了避免过多的散列冲突,散列表装载因子不能太大,特别是基于开放寻址法解决冲突的散列表,不然会浪费一定的存储空间。 |
122 | 129 |
|
123 | 130 | ## 参考资料 |
124 | 131 |
|
125 | | -- [https://zh.wikipedia.org/wiki/树\_(数据结构)](<https://zh.wikipedia.org/wiki/树_(数据结构)>) |
| 132 | +- [数据结构与算法之美](https://time.geekbang.org/column/intro/100017301) |
0 commit comments