# 归并排序
- 时间复杂度
O(nlogn) - 空间复杂度
O(n) - 稳定
思想:将数组拆分直到子数组只有一个数字,然后将子数组合并成一个包含两个数字的有序数组,然后在合成四个数字的有序数组直到整个数组完成排序
/* 模拟数组 */
var a = new Array(20);
for (let i = 0; i < a.length; ++i) {
a[i] = ~~(Math.random() * 100 + 1);
}
console.log("排序前:" + a);
let res = new Array(a.length);
mergeSort(a, 0, a.length - 1, res);
console.log("排序后:" + a);
function mergeSort(arr, start, end, res) {
// 只有一个数字,停止拆分
if (start == end) return;
let mid = Math.floor((start + end) / 2);
// 拆分左边
mergeSort(arr, start, mid, res);
// 拆分右边
mergeSort(arr, mid + 1, end, res);
// 合并左右
merge(arr, start, end, res);
}
function merge(arr, start, end, res) {
let mid1 = Math.floor((start + end) / 2);
let mid2 = mid1 + 1;
// 两个子数组 双指针
let index1 = start,
index2 = mid2;
while (index1 <= mid1 && index2 <= end) {
// 这里等号保证稳定性
if (arr[index1] <= arr[index2]) {
res[index1 + index2 - mid2] = arr[index1++];
} else {
res[index1 + index2 - mid2] = arr[index2++];
}
}
// 有剩余直接加入到最后
while (index1 <= mid1) {
res[index1 + index2 - mid2] = arr[index1++];
}
while (index2 <= end) {
res[index1 + index2 - mid2] = arr[index2++];
}
while (start <= end) {
arr[start] = res[start++];
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
原地归并排序(不使用额外空间):
/* 模拟数组 */
var a = new Array(20);
for (let i = 0; i < a.length; ++i) {
a[i] = ~~(Math.random() * 100 + 1);
}
console.log("排序前:" + a);
mergeSort(a, 0, a.length - 1);
console.log("排序后:" + a);
function mergeSort(arr, start, end) {
// 只有一个数字,停止拆分
if (start == end) return;
let mid = Math.floor((start + end) / 2);
// 拆分左边
mergeSort(arr, start, mid);
// 拆分右边
mergeSort(arr, mid + 1, end);
// 合并左右
merge(arr, start, end);
}
function merge(arr, start, end) {
let mid = Math.floor((start + end) / 2);
// 两个子数组 双指针
let index1 = start,
index2 = mid + 1;
while (index1 <= mid && index2 <= end) {
if (arr[index1] > arr[index2]) {
[arr[index1], arr[index2]] = [arr[index2], arr[index1]];
// 交换后如果后面有更小的往前移动
if (index2 != end) {
let v = arr[index2];
let i = index2;
while (i < end && arr[i + 1] < v) {
arr[i] = arr[i + 1];
i++;
}
arr[i] = v;
}
}
index1++;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
原地归并排序本质上还是插入排序,虽然空间复杂度比归并低但是时间效率更差