1. 基本原理
在上篇文章中介绍了归并排序的递归实现,虽然递归的实现方式很简单,通过递归调用就可以实现,但是会占用大量的时间和空间,使得算法的效率下降;使用迭代的方式代替递归的方式虽然会使得代码的编写变得困难,但是会增大效率。
递归的思想实际上是从上往下“递”,再从下往上“归”。递归的实现过程可以看成如下的过程
而迭代的过程就是化成一个个小的排序问题,再合并到一起,比如如下的过程
2. 代码实现
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 10
void MergeSort(int k[], int n)
{
// i 用于 for 循环迭代,temp 用来存储临时数组,所以要给他分配内存
int i, next, left_min, left_max, right_min, right_max;
int *temp = (int *)malloc(n * sizeof(int));
// i 是步长,第一次是1个元素与1个元素相比,第2个是两个元素与2个元素相比
for( i=1; i < n; i*=2 )
{
// left_min 最后是要小于 n-i 的,这一点可以通过画图得到
// left_min = right_max 是指上一组排序完成之后,将上一组的 right 赋值给下一组的 left_min
for( left_min=0; left_min < n-i; left_min = right_max )
{
right_min = left_max = left_min + i;
right_max = left_max + i;
// 因为奇数的数组最后很有可能 right_max > n,所以将它限制到最大为 n
if( right_max > n )
{
right_max = n;
}
next = 0;
// 在这里跟递归中的归并操是一样的,从两个数组中取小的出来放入临时数组
while( left_min < left_max && right_min < right_max )
{
if( k[left_min] < k[right_min] )
{
temp[next++] = k[left_min++];
}
else
{
temp[next++] = k[right_min++];
}
}
// 但是上面的过程并不会同时将左右两个数组的元素都放入临时存储数组 temp 中
// 要么左边会剩一点,要么右边会剩一点,所以这个时候要对剩余的进行操作
// 如果左边剩了,说明这些应该是最大的,应该放在数组的右边
while( left_min < left_max )
{
k[--right_min] = k[--left_max];
}
// 将临时存储的元素放入数组中得到最后的结果
while( next > 0 )
{
k[--right_min] = temp[--next];
}
}
}
}
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;
}
参考文献
[1]Q-WHai ,排序算法系列:归并排序算法