希尔排序的基本思想
把待排序的数据元素分成若干个小组,对同一小组内的数据元素用直接插入法排序;小组的个数逐次减少;当完成了所有数据元素都在一个组内的排序后,排序过程结束。希尔排序又称作缩小增量排序。希尔排序是在分组概念上的直接插入排序,即在不断减少组的个数时把原各小组的数据元素插入到新组中的合适位置上。
在讨论直接插入排序算法的时间复杂度时,我们曾指出,原始数据元素集合越接近有序,直接插入排序算法的时间效率越高。这个结论是希尔排序算法能够成立的基础。希尔排序算法把待排序数据元素分成若干小组,在小组内用直接插入排序算法排序,当把若干个小组合并为一个小组时,组中的数据元素集合将会接近有序,这样,各组内的直接插入排序算法的时间效率就很好,最终整个希尔排序算法的时间效率就很好。
算法实现
#include <stdio.h>
#include <stdlib.h>
typedef int KeyType;
typedef struct{
KeyType key;
}DataType;
/*希尔排序,对数组a[]排序,d[0]-d[numOfD-1]为希尔增量*/
void ShellSort(DataType a[], int n, int d[], int numOfD){
int i,j,k,m,span;
DataType temp;
for(m=0;m<numOfD;m++){//共循环numOfD次
span = d[m];//取本次的增量值
for(k=0;k<span;k++){//共span个小组
for(i=k;i<n-span;i=i+span){//组内是直接插入排序,区别是,每次不是增1
temp = a[i+span];
j = i;
while(j>-1&&temp.key<=a[j].key){
a[j+span] = a[j];
j = j-span;
}
a[j+span] = temp;
}
}
}
}
void main(void){
int i=0;
DataType array[8]={1,5,2,9,8,4,6,0};
DataType array2[8];
printf("原数组顺序:");
for(i=0;i<8;i++){
printf("%d ",array[i]);
}
printf("\n\n");
ShellSort(array,8,array2,8);
printf("希尔插入排序之后结果:");
for(i=0;i<8;i++){
printf("%d ",array[i]);
}
getch(0);
}
算法分析
在图中所示的例子中,增量分别取6, 3, 1。当增量d[0]=6时,共分了6个小组,在每个小组内按直接插入排序算法排序,这里的直接插入排序算法和10.2.1节讨论的直接插入排序算法的区别只是每次不是增1,而是增span。当增量d[2]=1的排序过程结束后,整个希尔排序过程就结束了。
比较希尔排序算法和直接插入排序算法,直接插入排序算法是两重循环,希尔排序算法是四重循环,但分析希尔排序算法中四重循环的循环次数可以发现,外面两重的循环次数都很小,并且当增量递减、小组变大时,小组内的数据元素数值已基本有序,而我们知道,越接近有序时,直接插入排序算法的时间效率越好。因此,希尔排序算法的时间复杂度较直接插入排序算法的时间复杂度改善很多。希尔排序算法的时间复杂度分析比较复杂,实际所需的时间取决于各次排序时增量的个数和增量的取值。研究证明,若增量的取值比较合理,则希尔排序算法的时间复杂度约为O(n(lbn)^2)。
希尔排序算法的空间复杂度为O(1)。由于希尔排序算法是按增量分组进行的排序,所以希尔排序算法是一种不稳定的排序算法。