归并排序

本篇简单讲述一下归并排序以及时间复杂度

  • 归并排序思想
  • 代码实现
  • 过程分析
  • 时间复杂度和空间复杂

归并排序

归并排序(Merging Sort)就是将两个或者两个以上的有序表合并成一个有序表的过程。将两个有序表合并成一个有序表的过程2-路归并

归并排序算法的思想是:

假设初始序列含有n个记录,则可看成n个有序的子序列,每个子序列的长度为1,然后两两归并,得到[n/2]个长度为2或1的子序列;再两两归并, ….., 如此重复,直至得到一个长度为n的有序序列为止。

代码实现

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
public class MergeSort {
public static void mergeSort(int[] arr){
if(arr == null || arr.length < 2){
return;
}
mergeSort(arr, 0, arr.length - 1);
}

private static void mergeSort(int[] arr, int left, int right){
if(left == right){
return;
}
int mid = left + ((right-left) >> 1); // <--> (l+r)/2
mergeSort(arr, left, mid);
mergeSort(arr, mid + 1, right);
// left - mid mid+1 - right 两个序列已经排好序,但整体无序
// merge的过程就是将两个序列排序
merge(arr, left, mid, right);
}

private static void merge(int[] arr, int left, int m, int right) {
// 申请辅助数组,存放合并后的序列
int[] help = new int[right - left + 1];
int i= 0;
int p1 = left;
int p2 = m + 1;
while(p1 <= m && p2 <= right){
help[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
}
// 两个必有且只有一个越界
// 两个循环只会执行一个
while (p1 <= m) {
help[i++] = arr[p1++];
}
while (p2 <= right) {
help[i++] = arr[p2++];
}
for (i = 0; i < help.length; i++) {
arr[left + i] = help[i];
}
}
}

动画演示

图片来源:https://mp.weixin.qq.com/s/vn3KiV-ez79FmbZ36SX9lg

归并排序-动画演示

merge过程:

merge

1
2
3
4
5
6
7
8
while (p1 <= m) {
help[i++] = arr[p1++];
}
while (p2 <= right) {
help[i++] = arr[p2++];
}

p1,p2每次只会移动一个,所以必定会有一个越界。如果p1耗尽,需要把p2后面内容拷贝至help数组,反之。

时间复杂度

当有n个记录时,需进行$\lceil log_2n \rceil$躺归并排序,其关键字比较次数不超过n,元素移动次数都是n,因此,归并排序的时间复杂度为$O(nlog_2n)$。

空间复杂度

用顺序表实现归并排序时,需要和待排序记录个数相等的辅助存储空间,所以空间复杂度为O(n)。

特点

归并排序是一种稳定的排序

0%