归并排序的思想是:将两个有序的子序列通过归并得到一个大的子序列实现序列有序化
算法实现过程如下:
1、将数组划分为一个个最小的子序列,即每个子序列只有一个元素
2、将最小的子序列两两归并得到大的子序列
3、递归执行步骤2,直到归并得到最大的序列,即有序的整个序列
比如如下序列:
16 9 8 20 7 9 6 5
先将序列递归划分成最小的子序列
16 9 8 20 | 7 9 6 5
16 9 | 8 20 | 7 9 | 6 5
16 | 9 | 8 | 20 | 7 | 9 | 6 | 5
将子序列依次归并得到最终有序序列,比如序列16 | 9归并后为9 16
9 16 | 8 20 | 7 9 | 5 6
8 9 16 20 | 5 6 7 9
5 6 7 8 9 9 16 20
归并排序是一种稳定的排序算法。
空间复杂度:归并排序需要一个与原序列等长的空间作为归并时的缓存用,所以空间复杂度为O(n);
时间复杂度:归并排序的时间主要花费在归并操作上,因为是对有序的子序列归并,只需要扫描一遍子序列元素,
因此一次归并操作花费的时间是O(n),归并排序将序列划分成log2n种子序列长度不同的序列,因此需要归并操作
log2n次,所以时间复杂度是O(nlog2n),但是每次归并完成后,需要将归并后的元素拷贝回原序列,因此通常
花费的时间会比快速排序多。
针对已经有序的排序,归并排序可以在归并时对比两子序列的最小元素和最大元素,如果已经有序,则跳过归并
过程,这样时间复杂度就为O(n)
算法代码实现如下:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 /* 用时间做种子产生随机数 */ 5 #include <time.h> 6 7 #define MAXLEN 50 8 static int tmp[MAXLEN]; 9 10 void ms(int A[], int left, int right) 11 { 12 /* 13 * left是数组左下标 14 * right是数组右下标 15 */ 16 int mid, l, r, k; 17 18 if (A == NULL || left >= right) { 19 return; 20 } 21 22 mid = (left + right) / 2; 23 ms(A, left, mid); 24 ms(A, mid + 1, right); 25 26 l = left; 27 r = mid + 1; 28 k = 0; 29 while (l <= mid && r <= right) { 30 if (A[l] <= A[r]) { 31 tmp[k++] = A[l++]; 32 } 33 else { 34 tmp[k++] = A[r++]; 35 } 36 } 37 38 while (l <= mid) { 39 tmp[k++] = A[l++]; 40 } 41 42 while (r <= right) { 43 tmp[k++] = A[r++]; 44 } 45 46 /* 将有序的tmp拷贝到数组A中 */ 47 k = 0; 48 for (l = left; l <= right; l++) { 49 A[l] = tmp[k++]; 50 } 51 52 } 53 54 static void printA(int A[], int len) 55 { 56 int i; 57 58 for (i = 0; i < len; i++) { 59 printf("%d ", A[i]); 60 } 61 printf("\n"); 62 } 63 64 int main(int argc, char **argv){ 65 int i, res, len; 66 int A[50]; // = {-1,6,2,3,9,19}; 67 68 srand((int)time(NULL)); 69 len = rand() % 51; //51; 70 printf("len is %d.\n", len); 71 72 srand((int)(time(NULL) + len)); 73 for (i = 0; i < len; i++) { 74 A[i] = rand() % 100; 75 } 76 77 printf("before sort :\n"); 78 printA(A, len); 79 80 ms(A, 0, len - 1); 81 82 printf("after sort :\n"); 83 printA(A, len); 84 85 return 0; 86 }