归并排序法

归并排序法是利用递归和分治技术,将数据序列划分为越来越小的半子表,再对半子表排序,最后再用递归步骤将排好序的半子表合并为越来越大的有序序列。

其中,“归”代表的是递归的意思,即递归地将数组折半地分离为单个数组。例如:数组[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 }
MergeSort.cpp

 

posted @ 2017-03-28 11:27  ren_zhg1992  阅读(185)  评论(0)    收藏  举报