归并排序

  #返回上一级

@Author: 张海拔

@Update: 2014-01-14

@Link: http://www.cnblogs.com/zhanghaiba/p/3518324.html

 

 1 /*
 2  *Author: ZhangHaiba
 3  *Date: 2014-1-13
 4  *FIle: merge_sort.c
 5  *
 6  *merge sort demo
 7  */
 8 
 9 #include <stdio.h>
10 #define N 512
11 #define INF 0x7fffffff //sentinel
12 
13 void merge_sort(int *, int, int);
14 void set_array(int *, int);
15 void show_array(int *, int);
16 
17 int array[N];
18 int left_tmp[N/2 + 10]; //save INF to a[array_len] as sentinel
19 int right_tmp[N/2 + 10];
20 
21 int main(void)
22 {
23     int n;
24 
25     scanf("%d", &n);
26     set_array(array, n);
27     merge_sort(array, 0, n-1);
28     show_array(array, n);
29     return 0;
30 }
31 
32 
33 void merge_sort(int *a, int l, int r)
34 {
35     if (l >= r) return;
36     else {
37         int m = l + (r-l)/2; //partition
38         merge_sort(a, l, m);
39         merge_sort(a, m+1, r);
40         int left_len = m-l+1, right_len = r-m, i, j = l;
41         for (i = 0; i < left_len; ++i, ++j)
42             left_tmp[i] = a[j];
43         left_tmp[i] = INF;
44         for (i = 0; i < right_len; ++i, ++j)
45             right_tmp[i] = a[j];
46         right_tmp[i] = INF;
47         for (i = j = 0; l <= r; ++l) //merge order list    
48             a[l] = left_tmp[i] <= right_tmp[j] ? left_tmp[i++] : right_tmp[j++];
49     }
50 }
51 
52 void set_array(int *a, int n)
53 {
54     int i;
55 
56     for (i = 0; i < n; ++i)
57         scanf("%d", a+i);
58 }
59 
60 
61 void show_array(int *a, int n)
62 {
63     int i;
64 
65     for (i = 0; i < n; ++i)
66         printf(i == n-1 ? "%d\n" : "%d ", a[i]);
67 }

 

归并排序,是分治法的典范。

如果你理解了二叉树的前序遍历和后序遍历,就不难写出归并排序。

归并和快排一样,有一个划分过程。不过这里的归并完全是二分的。划分在前序遍历过程中(边划分边处理子数组),而归并体现在后序遍历过程中。

归并过程:首先复制左右子数组分别放在left_tmp和right_tmp数组中,然后通过有序表的合并算法放回根数组[l, r]中。

显然归并过程是从叶子数组开始的(回溯开始于前进的结束),而叶子数组只有一个元素,必定是有序的。所以说归并的过程核心是有序表的合并算法。

有序表的合并算法其时间复杂度显然是O(n),从整个二分归并树来看,横向看子数组的连起来的长度肯定是n,纵向看树高为lgn。

所以算法的时间复杂度相当稳定,就是O(n*lgn)。

 

上述实现中,注意:

(1)引入INF存入临时数组有效数据的下一个位置作为哨兵,这样方便简单实现有序表合并算法,因此临时数组长度应该略大于N/2,防止极端情况数组越界。

(2)归并排序一大特征就是:该算法是稳定的。所以在有序表合并时,注意要用"<="而非"<",这样才能确保相同关键字排序后相对前后位置不会改变。

 

  #返回上一级

posted @ 2014-01-14 01:06  张海拔  阅读(431)  评论(0编辑  收藏  举报