前言
希尔排序是一种基于插入排序的排序算法,经过改动,它解决了插入排序所存在的问题:对于大规模乱序数组插入排序会很慢,因为它只能交换相邻的元素。假设数组最小元素在末尾,升序排序中它就需要移动N-1次到数组开头。而希尔排序通过交换不相邻的元素对数组进行局部排序,最终用插入排序将局部有序数组进行最后排序。
思想及图解
希尔排序的思想是使数组中任意间隔为h的元素都是有序的。这样的数组被称为h有序数组。 ——《算法(第4版)》
如下图所示
如此,数组中的元素即可完成较大跨度的排序。
随着排序的进行,h不断减小,子数组的规模在不断增大,有序性不断提升,当h = 1时即相当于插入排序。此时整体数组已呈局部有序,此时对于插入排序而言效率非常之高。
代码实现
sort(array) {
const N = array.length;
let h = 1;
while(h < N/3){ //设置h
h = 3 * h + 1;
}
while(h >= 1){
//使数组变为h有序
for(let i = h; i < N; i++){
//将array[i]插入到array[i-h],array[i- 2*h],array[i - 3*h]
for(let j = i; j >= h && this.less(array[j], array[j-h]); j -= h){
this.exch(array, j, j-h);
}
}
h = Math.floor(h / 3);
}
}
如此便可通过h进行局部性的排序。
总结
由于h选择的原因,希尔排序目前的性能还没有被完全研究透彻,即使是如上代码对h的选择也是。
而在实际应用中,希尔排序适合中等大小的数组,它的代码量小,较为简单,同时不占同额外的空间。但是对于规模很大的数组,希尔排序的表现可能就没那没好了,不及有如快排等的算法。工程实践中,比如工程初始阶段可以使用希尔排序,而后续阶段再考虑是否使用更复杂的排序算法。
参考资料
《算法(第4版)》