希尔排序
希尔排序的由来是根据插入排序的。
读者若不了解插入排序,可以参考笔者的详解排序算法--插入排序和冒泡排序.
希尔排序是基于插入排序的以下两点性质而提出改进方法的:
- 插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率
- 但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位
希尔排序利用了插入排序的简单,同时又避免了插入排序每次交换只能消除一个逆序对的缺点。所以希尔排序一般不是交换相邻元素,而是跳跃一段距离交换。
算法思想
希尔排序通过将比较的全部元素分为几个区域来提升插入排序的性能。这样可以让一个元素可以一次性地朝最终位置前进一大步。然后算法再取越来越小的步长进行排序,算法的最后一步就是普通的插入排序,但是到了这步,需排序的数据几乎是已排好的了(此时插入排序较快)。
步长序列
步长的选择是希尔排序的重要部分。只要最终步长为1任何步长序列都可以工作。算法最开始以一定的步长进行排序。然后会继续以一定步长进行排序,最终算法以步长为1进行排序。当步长为1时,算法变为插入排序,这就保证了数据一定会被排序。
可能希尔排序最重要的地方在于当用较小步长排序后,以前用的较大步长仍然是有序的。比如,如果一个数列以步长5进行了排序然后再以步长3进行排序,那么该数列不仅是以步长3有序,而且是以步长5有序。如果不是这样,那么算法在迭代过程中会打乱以前的顺序,那就不会以如此短的时间完成排序了。
最优时间复杂度
O(n)不稳定
希尔排序动态图
Java代码:
package cc;
public class ShellSort {
public static void shellsort(int[] a) {
int n = a.length;
int j;
for(int d=n/2;d>0;d/=2) {/* 希尔增量序列 */
/* 插入排序 */
for(int p=d;p<n;p++) {
int temp = a[p];
for(j=p;j>=d && a[j-1] > temp;j=j-d)
a[j] = a[j-d];
a[j] = temp;
}
}
}
}