1月第317题:简单描述一下 “希尔排序” ?
希尔排序的基本思想是把数组按下标的一定增量分组,对每组使用直接插入排序 算法排序;随着增量逐渐减少,每组包含的元素越来越多,当增量减至 1 时, 整个数组恰被分成一组,算法便终止。
在上面这幅图中:
初始时,有一个大小为 10 的无序序列。
在第一趟排序中,我们不妨设 gap1 = N / 2 = 5,即相隔距离为 5 的元素组成一组,可以分为 5 组。
接下来,按照直接插入排序的方法对每个组进行排序。
在第二趟排序中,我们把上次的 gap 缩小一半,即 gap2 = gap1 / 2 = 2 (取整数)。这样每相隔距离为 2 的元素组成一组,可以分为 2 组。
按照直接插入排序的方法对每个组进行排序。
在第三趟排序中,再次把 gap 缩小一半,即gap3 = gap2 / 2 = 1。 这样相隔距离为 1 的元素组成一组,即只有一组。
按照直接插入排序的方法对每个组进行排序。此时,排序已经结束。
需要注意一下的是,图中有两个相等数值的元素 5 和 5 。我们可以清楚的看到,在排序过程中,两个元素位置交换了。
所以,希尔排序是不稳定的算法。
代码实现:
function hillSort(data) {
let gap = Math.floor(data.length / 2);
// 用于存储需要插入的数据
let temp;
// 注意i从gap开始,因为以data[0]为基准数,j=i-1
while (gap >= 1) {
for (let i = gap; i < data.length; i++) {
// 将第i个数保存,以供之后插入合适位置使用
temp = data[i];
// 因为前i-1个数都是从小到大的有序序列,只要当前比较的数(data[j-1])比temp大,就把这个数后移一位
// 这块j得用var声明,因为在for循环之外的作用域还要用j
for (var j = i - gap; j >= 0 && data[j] > temp; j = j - gap) {
data[j + gap] = data[j];
}
// 将temp插入合适的位置
data[j + gap] = temp;
}
gap = Math.floor(gap / 2);
}
return data;
}