代码
#include<stdio.h>
void shell_sort(Numli *pNumli);
// void insert_sort(int num[], int length); 插入排序
int main(){
int li[] = {8,12,5,9,2};
int n = sizeof(li)/sizeof(li[0]);
shell_sort(&test);
int i;
for (i = 0;i<test.n;i++){
printf("数组第%d个数是%d\n",(i+1),(test.num)[i]);
}
// 插入排序的简单测试
// li[] = {8,12,5,9,2};
// insert_sort(test.num,test.n);
// for (i = 0;i<test.n;i++){
// printf("数组第%d个数是%d\n",(i+1),(test.num)[i]);
// }
return 0;
}
void shell_sort(num[],n){
int gap = n / 2;
while(gap > 0){
int i = gap;
while(i < n){
int j = i;
while(j>=gap){
if(num[j-gap] > num[j]){
int temp = num[j-gap];
num[j-gap] = num[j];
num[j] = temp;
}else{
break;
}
j -= gap;
}
i ++;
int k;
for (k = 0;k<n;k++){
printf("%d ",num[k]);
}
printf("\n");
}
gap = gap / 2;
}
}
// 插入排序
/*
void insert_sort(int num[], int length){
int i = 1;
while(i < length){
int j = i;
while(j >= 1){
printf("j = %d\n",j);
if(num[j-1] > num[j]){
int temp = num[j-1];
num[j-1] = num[j];
num[j] = temp;
}else{
break;
}
j --;
}
i ++;
}
}
*/
想法
希尔排序是插入排序的升级版,只不过其对于个数超过3个的数组,则将数组不断划分为2、4、……、n(当数组个数除以n的结果为1时就变成了插入排序)个部分不断分而治之。
为了记忆的方便,应该记住:
插入排序有两层循环,第一层循环,是要把整个数组的第二个数、第三个数、……、第n个数都拿出来和前面已经排好的有序数组进行比较;第二层循环是拿出来那个数之后,从有序数组的最后一个数开始,还得不断向前比,直到碰到比它小的,才在这里把它安置下来。也就是说,第一层循环是要不断从待排序数组中那数出来,第二层循环嵌套在第一层循环里,第二层循环是要把有序数组中的数拿出来和第一层循环里拿出来的数比,确认把那个数放到什么位置。
而希尔排序则还要多一层循环,这一层循环套在最外面?做什么呢?
则将数组不断划分为2、4、……、n(当数组个数除以n的结果为1时就变成了插入排序)
干这件事情。
希尔排序的第二层循环,也就是不断从待排序数组里取数的那个循环,很值得理解一下。
第一,它的起始条件是i=gap;如果想希尔排序是插入排序的进化版,而插入排序里起始i=1,相当于插入排序里gap=1;然而若深究,个人觉得这样理解更好——在插入排序中为何i从1起步,因为整组数据被划分为有序数组和待排序数组两个部分组成,而从整组数据里取第一个数出来,一个数的数组肯定是有序的,之后待排序数组和它比较,不断插入增长;那么希尔排序呢?希尔排序首先先把整组数据分为了gap组,然后相当于要对每组进行插入排序,对每一组进行插入排序,那每一组的第一个数都要被按出来当一个“有序数组”用。所以说,第二层循环是从待排序数组里取数,当然不可能从前gap个里开始。而之后gap/=2,则组又重新分为了gap/=2个,i又再度等于gap……实际上的道理是一样的,最后i=1;
第二,i变更的方式是i++,而并非是i+=gap。这其实是让人觉得很不完美的,这表明实际上希尔排序并不是说划分组A,B结束后,先把A全部排好,然后再去拍B,它只是通过控制步长,使得第一次排A1这个数,是跟A0(A组第一个数被拿出来当做有序数组)这个数去比,然后下一次是B1和B0去比,现在总共只有两组,那下一次就是A2和(A0,A1)去比,也就是说尽管数之间的比较是在同一组中发生的,但并非排好A组再拍排B组。