任意給出一行隨機數,對這些隨機數從小到大,進行歸併排序。
這裏只是簡單的沒有用到遞歸,後續的改進算法思想:1、不回寫(減少這裏copy()函數),2、不逆序,(組合片段時,選擇那些已經是順序的片段,例如(3,5,6),(4),(2),(7,8)),3、與插入結合(因爲可以證明,當每個片段的長度<=16時,插入排序較好,所以可以選擇片度小於16的進行插入排序,然後進行歸併)。
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define LEN 37
void merge(int i, int j, int d);
void print(int a[]);
void copy();
int a[LEN];
int b[LEN];
void main(void)
{
int i,j,d;
srand((unsigned int)time(NULL));
for(i=0; i<LEN; i++)
{
a[i]=rand()%LEN+1;
}
printf("排序之前的序列:\n");
print(a);
printf("\n");
//歸併的基本思想:把一個長序列,先一個數佔一個片段,然後兩兩按序合併,合併的有序的片段再與其它
//合併的有序片段進行合併,直到整個序列都是有序的,
//用i表示第一個片段的起始位置,用j表示第二個片段的起始位置,
//d表示兩個片段之間的跨度,進行兩兩合併
d=1;
while(d<LEN)
{
i=0;
j=i+d;
while(j<LEN+1)
{
merge(i,j,d);
//定位下一對片段位置
i=i+2*d;
j=j+2*d;
}
d=2*d; //新的跨度
copy();
//printf("\n***a[0]=%d***\n",a[0]);
}
printf("排序之後的序列:\n");
print(b);
printf("\n");
}
//把兩個有序序列合併到一個序列中
void merge(int i, int j, int d)
{
int k=i;
int leni=i+d;
int lenj;
if(j+d>LEN)
{
lenj=LEN;
}
else
{
lenj=j+d;
}
while(i<leni && j<lenj)
{
if(a[i]>a[j])
{
b[k]=a[j];
k++;
j++;
}
else
{
b[k]=a[i];
k++;
i++;
}
}
while(i<leni)
{
b[k]=a[i];
i++;
k++;
}
while(j<lenj)
{
b[k]=a[j];
j++;
k++;
}
}
void print(int a[])
{
int i;
for(i=0; i<LEN; i++)
{
printf("%3d\t",a[i]);
}
}
void copy()
{
int i;
for(i=0; i<LEN; i++)
{
a[i]=b[i];
}
}