希尔排序
希尔排序(Shell’s Sort)是插入排序的一种又称“缩小增量排序”(Diminishing Increment Sort),是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因D.L.Shell于1959年提出而得名。
希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。
言简意赅,希尔排序的实质就是插入排序。但是希尔排序的优化就是将一个长的序列,利用步长,分组开来,分组进行插入排序。最后一直到步长为 1 的时候,插入排序结束,这个过程就是希尔排序。由于使用插入排序的时候,如果这个带插入的序列基本有序,那么插入排序的效率是非常高的。而希尔排序正是利用了这个原则,进行分组,那么到最后的时候,插入的序列是一个大致有序的序列,效率会非常高。
思路
观察整个排序的过程,在选取步长的时候起初选取元素总个数除 2 ,接下来每次gap都除等于 2 。最后直至等于 1 。这个序列又叫做希尔序列。其实还有更高效的序列。希尔排序提高效率的一大方法就是选取一个好的序列。
实现
void ShellSort(int array[], int size)
{
if (size <= 1) {
return;
}
// 这里利用希尔序列作为希尔排序的步长
// 希尔序列 2 4 8 16...
int gap = size;
// 注:在使用步长时,一定要从 size 开始向下除
// 不能用 2^N 这样来计算
// 因为不一定 2^N 刚好等于 size
for (; gap > 0; gap /= 2) { // 步长控制循环
int cur = 0;
for(; cur < gap; ++cur) { // 每组起始元素
int bound = cur + gap;
for(; bound < size; bound += gap) { // 插入排序,不过每组元素间相差 gap
int bound_value = array[bound];
int index = bound - gap;
while (index >= 0 && bound_value < array[index]) {
array[index + gap] = array[index];
index -= gap;
}
array[index + gap] = bound_value;
} // end for (; bound < size; ++bound)
}
} // end for (; gdp <= size; gap *= 2)
return;
}
希尔排序其实就是一种变相的插入排序,它利用了插入排序的优点,并且避开其短处,插入排序在处理少数量元素时效率较高,希尔排序利用步长分组,从而达到分解一个大量数据域。最后gap为 1 的时候,此时的数据已经是一个大致有序的数列,这时候直接进行插入排序,效率依旧很高。
希尔排序的时间复杂度最好能到 O(N^1,3),最坏就是 O (N^2),如果选取一个好的gap序列,能够提高效率。空间复杂度为 O(1)。
欢迎大家共同讨论,如有错误及时联系作者指出,并改正。谢谢大家!