问题引入
插入排序法由未排序的后半部前端取出一个值,插入已排序前半部的适当位置,概念简单但速度不快。为加快插入排序法速度,让后一次的排序尽量利用前一次排序后的结果,以加快排序的速度,即采用Shell排序法。
问题分析
shell排序法过程如下:
假设要排序的元素有n个,每次进行插入排序时并不是所有的元素同时进行时,而是取一段间隔。Shell首先将间隔设定为n/2,然后跳跃进行插入排序;再将间隔n/4,跳跃进行排序动作;再设定间隔为n/8、n/16等,直到间隔为1之后的最后一次排序终止。由于上一次的排序动作都会将 固定间隔内的元素排序好,所以间隔越来越小时,某些元素位于正确位置的机率越高,因此靠后的排序会较快。
例如:
89 12 65 97 61 81 27 2 61 98
总共10个数,第一次将间隔设定为10 / 2 = 5,此时对间隔为5的数字进行排序,如下所示(连线部分表示要一起进行排序的部分):
再将间隔设定为5 / 2的商,也就是2,此时对间隔为2的数字进行排序,如下所示(连线部分表示要一起进行排序的部分):
再设定为间隔为2 / 2 = 1,此时对间隔为1的数字进行排序,相当于进行一次插入排序,如下所示(连线部分表示要一起进行排序的部分),此时基本已成型,不用大幅度排序:
代码实现
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define MAX 10
#define SWAP(x,y) {int t; t = x; x = y; y = t;} //宏定义交换元素数据函数SWAP
void shellsort(int[]);
int main(){
int number[MAX] = {0};
int i;
srand(time(NULL)); //刷新每次产生的随机数,若无此句,每次随机数相同,亲自尝试一下便知
printf("排序前:");
for(i = 0; i < MAX; i++){
number[i] = rand() % 100; //产生0-99的随机数,这里没有采用固定的数组值进行排序,随机生成
printf("%d ", number[i]);
}
shellsort(number);
return 0;
}
void shellsort(int number[]){
int i, j, k, gap, t;
gap = MAX / 2;
while(gap > 0){
for(k = 0; k < gap; k++){
for(i = k+gap; i < MAX; i+=gap){
for(j = i - gap; j >= k; j-=gap){
if(number[j] > number[j+gap]){
//交换元素位置,也可以将交换语句写在函数体内部
SWAP(number[j], number[j+gap]);
}else{
break;
}
}
}
}
printf("\ngap = %d:", gap);
for(i = 0; i < MAX; i++){
printf("%d ", number[i]);
}
printf("\n");
gap /= 2;
}
}