归并排序法
归并排序法是利用递归和分治技术,将数据序列划分为越来越小的半子表,再对半子表排序,最后再用递归步骤将排好序的半子表合并为越来越大的有序序列。
其中,“归”代表的是递归的意思,即递归地将数组折半地分离为单个数组。例如:数组[2,6,1,0]会先折半,分为[2,6]和[1,0]两个数组,然后再次折半,将数组分离,分为[2],[6],[1],[0]。
“并”的思想就是将分开的数组按照顺序放到另一个数组中。如上面的[2]、[6]合并到一个数组中是[2,6],[1],[0]合并为[0,1],然后再将[2,6]和[0,1]合并到一个数组中,即为[0,1,2,6]。
具体而言,将待排序序列R[0...n-1]看成是n个长度为1的有序序列,将相邻的有序表成对归并,得到n/2(向上取整)个长度为2或1的有序表;将这些有序序列再次归并,反复执行,直到得到一个有序序列为止。
综上可知:
归并排序其实要做两件事:
(1)“分解”——将序列每次折半划分。
(2)“合并”——将划分后的序列段两两合并后排序。
我们先来考虑第二步,如何合并?
在每次合并过程中,都是对两个有序的序列段进行合并,然后排序。
这两个有序序列段分别为 R[low, mid] 和 R[mid+1, high]。
先将他们合并到一个局部的暂存数组R2中,带合并完成后再将R2复制回R中。
为了方便描述,我们称 R[low, mid] 第一段,R[mid+1, high] 为第二段。
每次从两个段中取出一个记录进行关键字的比较,将较小者放入R2中。最后将各段中余下的部分直接复制到R2中。
经过这样的过程,R2已经是一个有序的序列,再将其复制回R中,一次合并排序就完成了。
核心代码
1 void Merge(int array[], int low, int mid, int high) 2 { 3 int i = low;// i 是第一段序列的下标 4 int j = mid + 1; // j 是第二段下标 5 int k = 0; // k 是临时存放合并序列的下标 6 int* array2 = new int[high - low + 1]; //array2是临时合并序列 7 8 //扫描第一段和第二段序列,直到有一个扫描结束 9 while (i <= mid && j <= high) 10 { 11 //判断第一段和第二段去除的数哪个更小,将其存入合并序列,并继续向下扫描 12 if (array[i] <= array[j]) 13 { 14 array2[k] = array[i]; 15 i++; 16 k++; 17 } 18 else 19 { 20 array2[k] = array[j]; 21 j++; 22 k++; 23 } 24 } 25 26 //第一段序列没有扫描完,将其剩余全部复制到合并序列 27 while (i <= mid) 28 { 29 array2[k] = array[i]; 30 k++; 31 i++; 32 } 33 34 //第二段序列没有扫描完,将其剩余全部复制到合并序列 35 while (j <= high) 36 { 37 array2[k] = array[j]; 38 j++; 39 k++; 40 } 41 42 //将合并序列复制到原始序列中 43 for (k = 0, i = low; i <= high; i++,k++) 44 { 45 array[i] = array2[k]; 46 } 47 delete[] array2; 48 }
掌握了合并的方法,接下来,让我们来了解 如何分解。

核心代码:
int MergeSort(int array[], int low, int high) { int mid; if (low > high) return -1; if (low == high) return 0; if (low < high) { mid = (low + high) / 2; MergeSort(array, low, mid); MergeSort(array, mid + 1, high); Merge(array, low, mid, high); } }
时间复杂度
归并排序的形式就是一棵二叉树,它需要遍历的次数就是二叉树的深度,而根据完全二叉树的可以得出它的时间复杂度是O(n*log2n)。
空间复杂度
由前面的算法说明可知,算法处理过程中,需要一个大小为n的临时存储空间用以保存合并序列。
算法稳定性
在归并排序中,相等的元素的顺序不会改变,所以它是稳定的算法。
归并排序和堆排序、快速排序的比较
若从空间复杂度来考虑:首选堆排序,其次是快速排序,最后是归并排序。
若从稳定性来考虑,应选取归并排序,因为堆排序和快速排序都是不稳定的。
若从平均情况下的排序速度考虑,应该选择快速排序。
完整参考代码:
1 #include <iostream> 2 using namespace std; 3 4 void Merge(int array[], int low, int mid, int high) 5 { 6 int i = low;// i 是第一段序列的下标 7 int j = mid + 1; // j 是第二段下标 8 int k = 0; // k 是临时存放合并序列的下标 9 int* array2 = new int[high - low + 1]; //array2是临时合并序列 10 11 //扫描第一段和第二段序列,直到有一个扫描结束 12 while (i <= mid && j <= high) 13 { 14 //判断第一段和第二段去除的数哪个更小,将其存入合并序列,并继续向下扫描 15 if (array[i] <= array[j]) 16 { 17 array2[k] = array[i]; 18 i++; 19 k++; 20 } 21 else 22 { 23 array2[k] = array[j]; 24 j++; 25 k++; 26 } 27 } 28 29 //第一段序列没有扫描完,将其剩余全部复制到合并序列 30 while (i <= mid) 31 { 32 array2[k] = array[i]; 33 k++; 34 i++; 35 } 36 37 //第二段序列没有扫描完,将其剩余全部复制到合并序列 38 while (j <= high) 39 { 40 array2[k] = array[j]; 41 j++; 42 k++; 43 } 44 45 //将合并序列复制到原始序列中 46 for (k = 0, i = low; i <= high; i++,k++) 47 { 48 array[i] = array2[k]; 49 } 50 delete[] array2; 51 } 52 53 int MergeSort(int array[], int low, int high) 54 { 55 int mid; 56 if (low > high) 57 return -1; 58 if (low == high) 59 return 0; 60 if (low < high) 61 { 62 mid = (low + high) / 2; 63 MergeSort(array, low, mid); 64 MergeSort(array, mid + 1, high); 65 Merge(array, low, mid, high); 66 } 67 } 68 69 int main() 70 { 71 int i = 0; 72 int array[] = { 5, 4, 9, 8, 7, 6, 0, 1, 4, 2 }; 73 int len = sizeof(array)/sizeof(int); 74 MergeSort(array, 0, len - 1); 75 76 for (i = 0; i < len; i++) 77 printf("%d\n", array[i]); 78 getchar(); 79 80 return 0; 81 }

浙公网安备 33010602011771号