1. 基本原理
归并排序 (Merge Sort) 就是利用归并的思想实现的排序方法。他的原理是假设初始序列有 n 个记录,则可以看成是 n 个有序的子序列,每个子序列的长度为1,然后两两归并,得到 ⌈n/2⌉ ⌈ n / 2 ⌉ 个长度为1 或者2 的有序子序列;再两两归并,……,如此重复,直至得到一个长度为 n 的有序序列为止,这种排序 方法称为 2 路归并排序。
具体过程如下图所示
首先将数组两两进行排序,之后将得到的结果在再两两排序,之后再两两排序,直至整个数组排序完成。所以从算法的简单描述就可以看出,一种直觉的方法就是使用递归,但是我们这里也会同时介绍一种使用迭代的方法。
2. 代码实现
2.1 递归实现方法
#include <stdio.h>
#define MAXSIZE 10
// 实现归并,并把最后的结果存放到list1里
void merging(int *list1, int list1_size, int *list2, int list2_size)
{
int i, j, k, m;
int temp[MAXSIZE];
i = j = k = 0; // i 是 list 1 的下标,j 是 list 2 的下标,k 是索引临时变量 temp 的
while( i < list1_size && j < list2_size )
{
if( list1[i] < list2[j] )
{
temp[k++] = list1[i++];
}
else
{
temp[k++] = list2[j++];
}
}
将最大的依次追加在 temp 的尾部
while( i < list1_size )
{
temp[k++] = list1[i++];
}
while( j < list2_size )
{
temp[k++] = list2[j++];
}
// 将 temp 中所有的元素放入 list1 中
for( m=0; m < (list1_size + list2_size); m++ )
{
list1[m] = temp[m];
}
}
void MergeSort(int k[], int n)
{
if( n > 1) // 递归停止的参数
{
int *list1 = k; // 左半部分
int list1_size = n/2; // 左半部分的尺寸
int *list2 = k + n/2; // 右半部分
int list2_size = n - list1_size; // 右半部分的尺寸
MergeSort(list1, list1_size); // 递归调用自己
MergeSort(list2, list2_size);
merging(list1, list1_size, list2, list2_size); //实现归并
}
}
int main()
{
int i, a[10] = {5, 2, 6, 0, 3, 9, 1, 7, 4, 8};
MergeSort(a, 10);
printf("排序后的结果是:");
for( i=0; i < 10; i++ )
{
printf("%d", a[i]);
}
printf("\n\n");
return 0;
}
2.2 代码相关解释
在上述的代码中,比较难理解的部分是void merging()
,现在以最简单的情况模拟计算机对这部分代码进行执行。假设现在在 list1 和 list2 中都只有一个元素,如 list1 = {4}
,list2 = {2}
。在第一个 while 循环中,其中的void merging(temp[k++] = list1[i++])
实际上先进行temp[k] = list1[i]
,再进行k++
和i++
,所以第一个 while 循环是将两个元素之中较大的放入临时数组中,剩下的两个 while 循环是将最大的元素追加在数组的尾部,最后的是将临时存储的数组用 list1 进行保存。