归并排序是一个分治算法。归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个有序的子序列,再把有序的子序列合并为整体有序序列。merg() 函数是用来合并两个已有序的数组. 是整个算法的关键。看下面的描述对mergeSort函数的描述:
MergeSort(arr[], l, r) If r > l 1. 找到中间点,讲arr分为两部分: middle m = (l+r)/2 2. 对一部分调用mergeSort : Call mergeSort(arr, l, m) 3.对第二部分调用mergeSort: Call mergeSort(arr, m+1, r) 4. 合并这两部分: Call merge(arr, l, m, r)
下图来自维基百科,显示了完整的归并排序过程。例如数组{38, 27, 43, 3, 9, 82, 10}.
下面是C程序的实现:
1 #include<stdlib.h> 2 #include<stdio.h> 3 4 /*合并arr的左右两部分: arr[l..m] 和 arr[m+1..r] */ 5 void merge(int arr[], int l, int m, int r) 6 { 7 int i, j, k; 8 int n1 = m - l + 1; 9 int n2 = r - m; 10 11 /* create temp arrays */ 12 int L[n1], R[n2]; 13 14 /* 复制数据到 L[] 和 R[] */ 15 for(i = 0; i < n1; i++) 16 L[i] = arr[l + i]; 17 for(j = 0; j <= n2; j++) 18 R[j] = arr[m + 1+ j]; 19 20 /* 将两部分再合并到 arr[l..r]*/ 21 i = 0; 22 j = 0; 23 k = l; 24 while (i < n1 && j < n2) 25 { 26 if (L[i] <= R[j]) 27 { 28 arr[k] = L[i]; 29 i++; 30 } 31 else 32 { 33 arr[k] = R[j]; 34 j++; 35 } 36 k++; 37 } 38 39 /* 复制剩下的部分 L[] */ 40 while (i < n1) 41 { 42 arr[k] = L[i]; 43 i++; 44 k++; 45 } 46 47 /* 复制剩下的部分 R[] */ 48 while (j < n2) 49 { 50 arr[k] = R[j]; 51 j++; 52 k++; 53 } 54 } 55 56 /* 对数据arr排序,从l到r */ 57 void mergeSort(int arr[], int l, int r) 58 { 59 if (l < r) 60 { 61 int m = l+(r-l)/2; //和 (l+r)/2 一样, 但是可以避免溢出在 l 和 r较大时 62 mergeSort(arr, l, m); 63 mergeSort(arr, m+1, r); 64 merge(arr, l, m, r); 65 } 66 } 67 68 void printArray(int A[], int size) 69 { 70 int i; 71 for (i=0; i < size; i++) 72 printf("%d ", A[i]); 73 printf("\n"); 74 } 75 76 /*测试程序 */ 77 int main() 78 { 79 int arr[] = {12, 11, 13, 5, 6, 7}; 80 int arr_size = sizeof(arr)/sizeof(arr[0]); 81 82 printf("Given array is \n"); 83 printArray(arr, arr_size); 84 85 mergeSort(arr, 0, arr_size - 1); 86 87 printf("\nSorted array is \n"); 88 printArray(arr, arr_size); 89 return 0; 90 }
时间复杂度:O(nlogn) 空间复杂度:O(n) 稳定排序
归并排序的应用:
1) 对链表进行排序。其它排序算法如堆排序和快速排序不能对链表排序。参考:使用归并排序对链表进行排序
2) 计算一个数组中的逆序对。剑指offer(09)-数组中的逆序对[分治]
3) 外排序。
时间: 2024-10-12 12:51:37