Update the book based on the revised second edition (#1014)

* Revised the book

* Update the book with the second revised edition

* Revise base on the manuscript of the first edition
This commit is contained in:
Yudong Jin
2023-12-28 18:06:09 +08:00
committed by GitHub
parent 19dde675df
commit f68bbb0d59
261 changed files with 643 additions and 647 deletions
@@ -27,7 +27,7 @@
1. 前序遍历的首元素 3 是根节点的值。
2. 查找根节点 3 在 `inorder` 中的索引,利用该索引可将 `inorder` 划分为 `[ 9 | 3 1 2 7 ]`
3. 根据 `inorder` 划分结果,易得左子树和右子树的节点数量分别为 1 和 3 ,从而可将 `preorder` 划分为 `[ 3 | 9 | 2 1 7 ]`
3. 根据 `inorder` 划分结果,易得左子树和右子树的节点数量分别为 1 和 3 ,从而可将 `preorder` 划分为 `[ 3 | 9 | 2 1 7 ]`
![在前序遍历和中序遍历中划分子树](build_binary_tree_problem.assets/build_tree_preorder_inorder_division.png)
@@ -49,7 +49,7 @@
| 左子树 | $i + 1$ | $[l, m-1]$ |
| 右子树 | $i + 1 + (m - l)$ | $[m+1, r]$ |
请注意,右子树根节点索引中的 $(m-l)$ 的含义是“左子树的节点数量”,建议合下图理解。
请注意,右子树根节点索引中的 $(m-l)$ 的含义是“左子树的节点数量”,建议合下图理解。
![根节点和左右子树的索引区间表示](build_binary_tree_problem.assets/build_tree_division_pointers.png)
@@ -20,7 +20,7 @@
2. **子问题是独立的**:子问题之间没有重叠,互不依赖,可以独立解决。
3. **子问题的解可以合并**:原问题的解通过合并子问题的解得来。
显然,归并排序满足以上三判断依据。
显然,归并排序满足以上三判断依据。
1. **问题可以分解**:递归地将数组(原问题)划分为两个子数组(子问题)。
2. **子问题是独立的**:每个子数组都可以独立地进行排序(子问题可以独立进行求解)。
@@ -78,7 +78,7 @@ $$
- **汉诺塔问题**:汉诺塔问题可以通过递归解决,这是典型的分治策略应用。
- **求解逆序对**:在一个序列中,如果前面的数字大于后面的数字,那么这两个数字构成一个逆序对。求解逆序对问题可以利用分治的思想,借助归并排序进行求解。
另一方面,分治在算法和数据结构的设计中应用非常广泛。
另一方面,分治在算法和数据结构的设计中应用非常广泛。
- **二分查找**:二分查找是将有序数组从中点索引处分为两部分,然后根据目标值与中间元素值比较结果,决定排除哪一半区间,并在剩余区间执行相同的二分操作。
- **归并排序**:本节开头已介绍,不再赘述。
@@ -86,6 +86,6 @@ $$
- **桶排序**:桶排序的基本思想是将数据分散到多个桶,然后对每个桶内的元素进行排序,最后将各个桶的元素依次取出,从而得到一个有序数组。
- **树**:例如二叉搜索树、AVL 树、红黑树、B 树、B+ 树等,它们的查找、插入和删除等操作都可以视为分治策略的应用。
- **堆**:堆是一种特殊的完全二叉树,其各种操作,如插入、删除和堆化,实际上都隐含了分治的思想。
- **哈希表**:虽然哈希表并不直接应用分治,但某些哈希冲突解决方案间接应用了分治策略,例如,链式地址中的长链表会被转化为红黑树,以提升查询效率。
- **哈希表**:虽然哈希表并不直接应用分治,但某些哈希冲突解决方案间接应用了分治策略,例如,链式地址中的长链表会被转化为红黑树,以提升查询效率。
可以看出,**分治是一种“润物细无声”的算法思想**,隐含在各种算法与数据结构之中。
@@ -19,7 +19,7 @@
如下图所示,对于问题 $f(1)$ ,即当只有一个圆盘时,我们将它直接从 `A` 移动至 `C` 即可。
=== "<1>"
![规模为 1 问题的解](hanota_problem.assets/hanota_f1_step1.png)
![规模为 1 问题的解](hanota_problem.assets/hanota_f1_step1.png)
=== "<2>"
![hanota_f1_step2](hanota_problem.assets/hanota_f1_step2.png)
@@ -31,7 +31,7 @@
3. 最后将小圆盘从 `B` 移至 `C`
=== "<1>"
![规模为 2 问题的解](hanota_problem.assets/hanota_f2_step1.png)
![规模为 2 问题的解](hanota_problem.assets/hanota_f2_step1.png)
=== "<2>"
![hanota_f2_step2](hanota_problem.assets/hanota_f2_step2.png)
@@ -55,7 +55,7 @@
3.`C` 为目标柱、`A` 为缓冲柱,将两个圆盘从 `B` 移至 `C`
=== "<1>"
![规模为 3 问题的解](hanota_problem.assets/hanota_f3_step1.png)
![规模为 3 问题的解](hanota_problem.assets/hanota_f3_step1.png)
=== "<2>"
![hanota_f3_step2](hanota_problem.assets/hanota_f3_step2.png)
@@ -66,7 +66,7 @@
=== "<4>"
![hanota_f3_step4](hanota_problem.assets/hanota_f3_step4.png)
从本质上看,**我们将问题 $f(3)$ 划分为两个子问题 $f(2)$ 和子问题 $f(1)$** 。按顺序解决这三个子问题之后,原问题随之得到解决。这说明子问题是独立的,而且解可以合并。
从本质上看,**我们将问题 $f(3)$ 划分为两个子问题 $f(2)$ 和一个子问题 $f(1)$** 。按顺序解决这三个子问题之后,原问题随之得到解决。这说明子问题是独立的,而且解可以合并。
至此,我们可总结出下图所示的解决汉诺塔问题的分治策略:将原问题 $f(n)$ 划分为两个子问题 $f(n-1)$ 和一个子问题 $f(1)$ ,并按照以下顺序解决这三个子问题。