vlambda博客
学习文章列表

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;}