如果一个排序算法,每次只把诸项目移动一个位置,则它的平均运行时间至少要和n2成比例.因为在这个排序算法运行的过程当中,每个记录平均都必须遍历n / 3个位置,因此如果要对直接插入排序进行有效的,实质性的改进的话,就要有一种算法,它可以使记录做长距离的跳跃,而不是一步一步的挪动.
希尔排序也是一种插入排序,它是在直接插入的基础上改进而来的.它也可以叫做缩小增量排序.
直接插入排序在数据"基本有序"的时候效率是比较高的,希尔排序的思想就是先使数据基本有序后再直接插入排序.
算法:
把待排序的数据根据增量序列分阶段的分组进行直接插入排序.
代码:
const int MAX = 20 ;
int sedgewick[] = ... {19, 5, 1, 0} ;
void shellSort( int * A)
... {
int i, j, temp;
int *gap, *sed;
for (sed = sedgewick; *sed > MAX; sed++); //选取增量序列的一部分,最大增量应小于元素的个数.
for(gap = sed; *gap > 0; gap++)
for(i = *gap; i < MAX; i++)
...{
j = i - *gap;
while(j >= 0 && A[j] > A[j + *gap])
...{
temp = A[j];
A[j] = A[j + *gap];
A[j + *gap] = temp;
j -= *gap;
}
}
}
int main()
... {
int A[MAX];
int i;
int nums = MAX;
printf("Please input %d numbers: ", nums);
for(i = 0; i < MAX; i++)
scanf("%d", &A[i]);
shellSort(A);
for(i = 0; i < MAX; i++)
printf("%d ", A[i]);
return 0;
}
有关增量序列的:
希尔排序的运行时间跟所选的增量序列有关系,上面的程序所选的是Sedgewick增量序列,这个增量序列在实践中最为人所称道.它是根据9 * 4- 9 * 2+ 1 或者是 4 - 3 * 2 + 1这两个式子得来的.这个增列序列在最坏的情况下运行时间为O(N4 / 3),平均的情况是O(N7 / 6)
还有一种hibbard 增量,它是1, 3, 7, .......2k - 1.这个序列可以在实践和理论上给出更好的结果.
Donald E.Knuth在他的书中建议到可以选择下面的公式来产生增量序列:
设h1 = 1, hi + 1 = 3hi + 1,而且当hi - 2 >= N时以hi停止.
还应该提到的是,无论怎样选择增量序列,最后一个增量必定是1.另外一点,一定不要选2的幂次的增量,那样的话所有的增量都是偶数,并且公比是2,那会使你的希尔排序和直接插入排序相差无几,运行时间约为( ).