@@ -95,7 +95,7 @@ function selection(array) {
95
95
96
96
#### 归并排序
97
97
98
- 归并排序的原理如下。先通过中间数索引将数组分为左右两部分,然后先排序左边,再排序右边,再将左右排序一次 。假设我有一组数组 ` [3, 1, 2, 8, 9, 7, 6] ` ,中间数索引是 3,先排序数组 ` [3, 1, 2, 8] ` 。在这个左边数组上,继续拆分直到变成数组包含两个元素(如果数组长度是奇数的话,会有一个拆分数组只包含一个元素)。然后排序数组 ` [3, 1] ` 和 ` [2, 8] ` ,然后再排序数组 ` [1, 3, 2, 8] ` ,这样左边数组就排序完成,然后按照以上思路排序右边数组,最后将数组 ` [1, 2, 3, 8] ` 和 ` [6, 7, 9] ` 排序。
98
+ 归并排序的原理如下。递归的将数组两两分开直到最多包含两个元素,然后将数组排序合并,最终合并为排序好的数组 。假设我有一组数组 ` [3, 1, 2, 8, 9, 7, 6] ` ,中间数索引是 3,先排序数组 ` [3, 1, 2, 8] ` 。在这个左边数组上,继续拆分直到变成数组包含两个元素(如果数组长度是奇数的话,会有一个拆分数组只包含一个元素)。然后排序数组 ` [3, 1] ` 和 ` [2, 8] ` ,然后再排序数组 ` [1, 3, 2, 8] ` ,这样左边数组就排序完成,然后按照以上思路排序右边数组,最后将数组 ` [1, 2, 3, 8] ` 和 ` [6, 7, 9] ` 排序。
99
99
100
100
<div align =" center " ><img src =" https://user-gold-cdn.xitu.io/2018/4/13/162be13c7e30bd86?w=896&h=1008&f=gif&s=937952 " width =500 /></div >
101
101
@@ -111,7 +111,10 @@ function sort(array) {
111
111
function mergeSort (array , left , right ) {
112
112
// 左右索引相同说明已经只有一个数
113
113
if (left === right) return ;
114
- let mid = parseInt ((left + right) / 2 );
114
+ // 等同于 `left + (right - left) / 2`
115
+ // 相比 `(left + right) / 2` 来说更加安全,不会溢出
116
+ // 使用位运算是因为位运算比四则运算快
117
+ let mid = parseInt (left + ((right - left) >> 1 ));
115
118
mergeSort (array, left, mid);
116
119
mergeSort (array, mid + 1 , right);
117
120
@@ -135,6 +138,25 @@ function mergeSort(array, left, right) {
135
138
}
136
139
```
137
140
138
- 以上算法使用了递归的思想。递归的本质就是压栈,每递归执行一次函数,就将该函数的信息(比如参数,内部的变量,执行到的行数)压栈,直到遇到终止条件,然后出栈并继续执行函数。对于以上算法来说,第一个递归函数最终会在 ` left ` 和 ` right ` 都为 0 的情况下终止,然后执行下一个递归函数,传入的索引参数都是 1,所以递归都终止,这时 ` left ` 为 0 , ` mid ` 为 0,所以将 ` [3, 1] ` 排序,这时函数执行完毕并出栈,继续执行以上的操作。
141
+ 以上算法使用了递归的思想。递归的本质就是压栈,每递归执行一次函数,就将该函数的信息(比如参数,内部的变量,执行到的行数)压栈,直到遇到终止条件,然后出栈并继续执行函数。对于以上递归函数的调用轨迹如下
142
+
143
+ ``` js
144
+ mergeSort (data, 0 , 6 ) // mid = 3
145
+ mergeSort (data, 0 , 3 ) // mid = 1
146
+ mergeSort (data, 0 , 1 ) // mid = 0
147
+ mergeSort (data, 0 , 0 ) // 遇到终止,回退到上一步
148
+ mergeSort (data, 1 , 1 ) // 遇到终止,回退到上一步
149
+ // 排序 p1 = 0, p2 = mid + 1 = 1
150
+ // 回退到 `mergeSort(data, 0, 3)` 执行下一个递归
151
+ mergeSort (2 , 3 ) // mid = 2
152
+ mergeSort (3 , 3 ) // 遇到终止,回退到上一步
153
+ // 排序 p1 = 2, p2 = mid + 1 = 3
154
+ // 回退到 `mergeSort(data, 0, 3)` 执行合并逻辑
155
+ // 排序 p1 = 0, p2 = mid + 1 = 2
156
+ // 执行完毕回退
157
+ // 左边数组排序完毕,右边也是如上轨迹
158
+ ```
159
+
160
+
139
161
140
162
该算法的操作次数是可以这样计算:递归了两次,每次数据量是数组的一半,并且最后把整个数组迭代了一次,所以得出表达式 ` 2T(N / 2) + T(N) ` (T 代表时间,N 代表数据量)。根据该表达式可以套用 [ 该公式] ( https://www.wikiwand.com/zh-hans/%E4%B8%BB%E5%AE%9A%E7%90%86 ) 得出时间复杂度为 ` O(N * logN) `
0 commit comments