简图
说明
讲算法的时候都是递归形式的。这里简单写一个非递归的实现。
就是2、2归并排序,然后4、4归并排序,直到完成。不用递归分组。
注意,看网上一些代码实现,把归并条件写成 左边<右边,而不是 左边<=右边或者右边<左边。左边<右边这种写法导致的结果是使稳定排序变成了不稳定排序。
代码
#include <stdio.h>
#include <math.h>
#define N 11
int mergeSort(int n,int * arr,int *temp)
{ //非递归方式的归并排序
//第一步,循环取分组长度,从2的0次方开始,每次乘2,即1,2,4,8,16...不小于n结束
for (int groupLen=1;groupLen<n;groupLen=groupLen<<1)
{
int resCount=0;//临时数组temp的下标。存放每次归并结果放在temp中的位置
int groupCount=ceil(n*1.0/groupLen); //分组个数 ,不足一组也算一组
int mergeCount=groupCount>>1;//归并次数 ,2组归并一次。单组不用归并。
//第二步,循环做两个分组的归并处理。
for (int i = 0;i<mergeCount;i++)
{
int left = (i*groupLen)<<1; //左分组的开始位置
int leftSide=left+groupLen; //左分组的结尾位置。
int right=leftSide; //右分组的开始位置
int rightSide=(n<right+groupLen)?n:right+groupLen; //右分组的结尾位置。
//归并两个数组。归并操作可以封装一个inline函数而不影响性能。这就是非递归的好处。递归无法inline。
while (left<leftSide&&right<rightSide)
{ //归并: 把两个分组头部较小的一个放入临时数组。
if(arr[left]<=arr[right]) //如果用arr[left] < arr[right],则是不稳定排序了。
temp[resCount++]=arr[left++];
else temp[resCount++]=arr[right++];
}
while (left<leftSide) //左分组剩余部分拷贝到临时数组
temp[resCount++]=arr[left++];
while (right<rightSide) //右分组剩余部分拷贝到临时数组
temp[resCount++]=arr[right++];
for (left = i<<1; left < rightSide;left++) //把临时数组的归并结果数据拷贝回原数组。
arr[left] = temp[left];
}
}
}
//测试一下。
int main(){
int n = N;
int arr[N]={6,3,6,8,6,4,7,8,9,2,1};
int temp[N];
mergeSort(n,arr,temp);
for(int i = 0;i < n;i++)
printf("%d,",arr[i]) ; printf("\b \n");
}
结束。。。