算法 - 归并排序(Merge Sort)

算法描述:

  • a为待排序数组,n为数组长度
  • 把 a 一分为二
  • 对 a 左半部分排序
  • 对 a 右半部分排序
  • 把两部分合并,合并结果得是有序的
  • 其中对 a 左、右部分排序也是使用相同的算法

伪代码:

1
2
3
4
5
mergeSort(a) {
  mergeSort(a_left_part)
  mergeSort(a_right_part)
  merge(a_left_part, a_right_part)
}

算法复杂度分析:

1
2
3
4
5
6
7
T(1) = C   因为无法再分左右两半了,所以n=1时只需要常数时间
T(n) = 2 * T(n/2) + n    代表左右两半到时间 + 合并结果需要的时间
     = 2 * (2 * T(n/4) + n/2) + n = 4 * T(n/4) + 2 * n
     = 4 * (2 * T(n/8) + n/4) + 2 * n = 8 * T(n/8) + 3 * n
     = 8 * (2 * T(n/16) + n/8) + 3 * n = 16 * T(n/16) + 4 * n
     = ...
     = 2 ^ k * T(n/2^k) + k * n

当T(n/2^k)=T(1)时,k为log2n,公式变成

  • 2log2n * C + n * log2n
  • => n * C + n * log2n
  • => O(nlogn)

上面提到的k = log2n = 递归深度

 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
// a为待排序数组,start为排序区间开始,end为排序区间结束
public void merge_sort(int[] a, int start, int end) {
  if (start >= end) {
    return;
  }
  int mid = (start + end) / 2;
  merge_sort(a, start, mid);
  merge_sort(a, mid + 1, end);
  merge(a, start, mid, end);
}

public void merge(int[] a, int start, int mid, int end) {
  // 合并两个有序数组
  int i = start;
  int j = mid + 1;
  int k = 0;
  int[] tmp = new int[end - start + 1];
  while (i <= mid && j <= end) {
    if (a[i] <= a[j]) {
      tmp[k] = a[i];
      i++;
    } else {
      tmp[k] = a[j];
      j++;
    }
    k++;
  }
  while (i <= mid) {
    tmp[k] = a[i];
    i++;
    k++;
  }
  while (j <= end) {
    tmp[k] = a[j];
    j++;
    k++;
  }
  for (int x = 0; x < k; x++) {
    a[start + x] = tmp[x];
  }
}

版权

评论