希尔排序,又称缩小增量排序,也是一种插入排序方法。它与插入排序的不同之处在于,它会优先比较距离较远的元素。
希尔排序的核心在于间隔序列的设定。既可以提前设定好间隔序列,也可以动态地定义间隔序列。
希尔排序的基本思想是,将整个待排序记录序列分割成若干个子序列,然后对每一个子序列进行直接插入排序。具体如下:
(1)先取一个正整数分成d1,把全部记录d1个组,所有距离为d1的倍数的记录看成一组,然后在各组内进行插入排序
(2)然后去d2(d2<d1)
(3)重复上述分组和排序操作,知道di=1(i>=1)位置,即所有记录称为一个组,最后对这个组进行插入排序。一般选d1约为n/2,d2为d1/2,d3为d2/2,...,di=1
实现代码:
function shellSort(arr){
if(arr.length<2){return arr;}
var gap=Math.floor(arr.length/2);
var tmp;
while(gap>0){
for(var i=gap;i<arr.length;i++){
tmp=arr[i];
for(var j=i-gap;j>=0;j-=gap){
if(arr[j]>tmp){
arr[j+gap]=arr[j];
}else{
break;
}
}
arr[j+gap]=tmp;
console.log(arr);
}
gap=Math.floor(gap/2);
}
return arr;
}
结果测试:
由上可以看到,对于长度为9的数组,其间隔gap取值依次为4,2,1.
关于动态定义间隔序列,以下摘自搜索的一段实现代码,为了测试使用的gap取值,稍微修改了一下console.log()的打印内容:
function shellSort(arr) {
var len = arr.length,
temp,
gap = 1;
//console.time('希尔排序耗时:');
while(gap < len/5) { //动态定义间隔序列
gap =gap*5+1;
}
console.log(gap);
for (gap; gap > 0; gap = Math.floor(gap/5)) {
console.log(gap);
for (var i = gap; i < len; i++) {
temp = arr[i];
for (var j = i-gap; j >= 0 && arr[j] > temp; j-=gap) {
arr[j+gap] = arr[j];
}
arr[j+gap] = temp;
}
}
console.timeEnd('希尔排序耗时:');
return arr;
}
根据上面代码,在Chrome的打印台测试:
可以看到gap的取值依次是6,1,只进行了两次。