排序算法多种多样。今天介绍一种新的排序算法,希尔排序算法。
希尔排序(Shell Sort),是插入排序的一种改进版本。由唐纳得希尔教授(Donald Shell)于1959年提出,故得名。
希尔排序的基本思想是:将待排序列分割成若干子序列分别进行插入排序,具体分割的方式是由一个增量序列gap决定的,而这个gap由原数据的长度,每次折半得到(gap=length/2),直到2,1.。当gap=1时,整个序列作为一个整体对待,变成了普通的插入排序。
希尔排序算法的排序过程如下:
本例中,原始数据有20个数:36,28,78,69,55,45,99,12,7,8,5,21,27,33,81,88,66,10,19,26。假设按升序排序。则:
第一轮gap=20/2=10,即表示将原数据分成10组,每组两个,两者的指针相差gap(10),分别排序。
分组情况如下(注:此分组仅为虚拟分组,不移动各组数据的物理位置,以下同):
【36,5】、【28,21】、【78,27】、【69,33】、【55,81】、【45,88】、【99,66】、【12,10】、【7,19】、【8,26】
各组排序结果如下:
【5,36】、【21,28】、【27,78】、【33,69】、【55,81】、【45,88】、【66,99】、【10,12】、【7,19】、【8,26】
第一轮得到结果如下:
5,21,27,33,55,45,66,10,7,8,36,28,78,69,81,88,99,12,19,26
第二轮10/2=5,即上一步得到的数据分成5组,每组4个数,组内两数位置相差 gap=5,分组情况为:
【5,45,36,88】、【21,66,28,99】、【27,10,78,12】、【33,7,69,19】、【55,8,81,26】
各组排序结果如下:
【5,36,45,88】、【21,28,66,99】、【10,12,27,78】、【7,19,33,69】、【8,26,55,81】
第二轮排序结果为:
5,21,10,7,8,36,28,12,19,26,45,66,27,33,55,88,99,78,69,81
第三轮5/2,再将上一步得到的数据分成2组,每组10个数。分组情况为:
【5,10,8,28,19,45,27,55,99,69】、【21,7,36,12,26,66,33,88,78,81】
各组排序结果如下:
【5,8,10,19,27,28,45,55,69,99】、【7,12,21,26,33,36,66,78,81,88】
第三轮排序结果为:
5,7,8,12,10,21,19,26,27,33,28,36,45,66,55,78,69,81,99,88
第四轮1.,此时gap=1,将上步得到的数据当成一个整体看待,运用一遍插入排序即可得到最终结果。
5,7,8,10,12,19,21,26,27,28,33,36,45,55,66,69,78,81,88,99
本算法在DEV c++5.11平台验证通过。
/*
****************************************************************************
对数组内的一组数据进行升序/降序排序,采用希尔排序算法。
****************************************************************************
*/
#include <stdio.h>
//定义并实现希尔排序函数 ,传入三个参数,一个数据指针,一个数据大小,一个排序升降序标志
void ShellSort(int *num,int len,int order){
int i,j,temp,gap;
gap=len;
while (gap>1){
gap /= 2;//分组的间隔数,每间隔gap的数分成一组,len/2,len/4,len/8...2,1(折半分组)
for (i=gap;i<len;i++){//i指针从gap开始,至数组尾 ,每次加1,依次遍历
temp = num[i];//temp暂存i指针指向的数据,与j指针指向的数据进行比较
for(j=i-gap;j>=0;j-=gap)//j指针比i指针相差gap,每次递减gap
{
if (order!=0){
if (temp > num[j])
{
num[j + gap] = num[j];
}
else
{
break;
}
}
else{
if (temp < num[j])
{
num[j + gap] = num[j];
}
else
{
break;
}
}
}
num[j+gap] = temp;
}
}
}
int main() {
int i, j, temp;
int num[] = {36,28,78,69,55,45,99,12,7,8,5,21,27,33,81,88,66,10,19,26};
int len=sizeof(num)/sizeof(int);
int *p=num;
int order=0;
printf("数组中有%d个元素。它们分别是:\n",len);
for (i=0; i<len; i++) {
printf("%d,",num[i]);
}
printf("\n");
printf("请输入排序方式(0:升序,非0数字:降序):");
scanf("%d",&order);
ShellSort(p,len,order);
if (order != 0 ){
printf("\n降序排序结果如下:\n");
for (i=0; i<len; i++) {
printf("%d,",*p++);
}
printf("\n");
}else{
printf("\n升序排序结果如下:\n");
for (i=0; i<len; i++) {
printf("%d,",*p++);
}
printf("\n");
}
return 0;
}
程序运行结果如下,完美实现升序排序。