首页 > 代码库 > 排序和查找(5)-归并排序

排序和查找(5)-归并排序

归并排序是一个分治算法。归并(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) 外排序。

 

排序和查找(5)-归并排序