例:a[]={4,8,3,7,1,5,6,2}
自然归并排序指的是对数组先进行一次线性扫描,得到自然排好序的子数段{4,8},{3,7},{1,5,6},{2}。在对其进行两两合并成更大的排好序的数组。
#include <stdio.h>
#define N 8
int GetIndex(int a[N],int index[N]){
int i,j=0;
index[j++]=0;
for(i=0;i<N-1;i++)
{
if(a[i]>a[i+1])
index[j++]=i+1;
}
index[j++]=N;//后面mergesort中合并需要判断i的范围,否则index[i+2]-1无法表示。合并两个需要三个数组下标
return j;
}
void merge(int a[N], int left, int mid, int right) {
int i=left,j=mid+1,k=left;
int t;
int d[N];
while(i <= mid && j <= right) {
if(a[i] < a[j]){
d[k++] = a[i++];
} else {
d[k++] = a[j++];
}
}
if(i!=mid+1){
for(t=i;t<=mid;t++){
d[k++]=a[t];
}
}
if(j != right+1) {
for(t = j; t <= right; t++){
d[k++] = a[t];
}
}
for(i = left; i <= right; i++){ //把此次进行合并后的元素拷贝到原数组
a[i] = d[i]; //没有参与合并的数组元素不变.为了进行下一次自然分组。
}
}
void mergeSort(int a[N],int index[N]){
int length=GetIndex(a,index);
int i;
while(length!=2){
for(i=0;i<length-2;i+=2){// i+=2是每次合并两个 向右移动两个
merge(a,index[i],index[i+1]-1,index[i+2]-1);
}
length=GetIndex(a,index);
}
}
void print(int n,int a[])
{ int i;
for(i=0;i<n;i++)
{if (i!=n-1) printf("%d, ",a[i]);
else printf("%d", a[i]);
}
printf("\n");
}
int main()
{
int a[N]={4,8,3,7,1,5,6,2};
int index[N];
print(N,a);
mergeSort(a,index);
print(N,a);
return 0;
}
运行结果: