希尔排序

我们还记得,插入排序的思路是:

1、外循环依次拿出第二个到最后一个元素,记作temp。

for (let i = 1; i < length; i++) {
          let temp = this.array[i]

2、将temp与它前面的元素依次进行比较。定义一个指针j指向前面的元素

let j = i
...
    j--

3、如果temp较小,则将另一个被比较的元素右移;

this.array[j] = this.array[j - 1]

4、如果temp较大,或前面没有元素了,则终止比较,并将temp插入回数组。

while (this.array[j - 1] > temp && j > 0){
  ...
}
 this.array[j] = temp

我们对插入排序做一点小小的改进,即第二步中,不再让temp和它前面的元素都进行比较,而是每隔若干个再进行一次比较,间隔数目记作gap。所以 j-- 变为j -= gap

与之对应,第一步中外循环就只需要从gap开始拿元素即可;第三步中右移填充也需要填到间距为gap的位置,第四步中的终止条件也要改成:“如果temp较大,或前面只有gap - 1个元素了,则终止比较”。

我们把gap作为排序算法的一个参数,调用时再传入,这样代码变成了下面的样子:

       ArrayList.prototype.insertionSort = function (gap) {
        let length = this.array.length
        //  依次获取从gap开始到最后一个元素
        for (let i = gap; i < length; i++) {
          //  外循环获取的元素,和它之前的元素依次比较
          let temp = this.array[i]
          //  j指向之前的元素
          let j = i
          while (this.array[j - gap] > temp && j > gap - 1) {
            this.array[j] = this.array[j - gap]
            j -= gap
          }
          this.array[j] = temp
        }
      } 

原来的插入排序相当于这个新算法中gap = 1 的特殊情况。

而希尔排序就是不断修改gap的值,反复调用这个新算法。gap的初值为数组长度的一半向下取整,之后不断地减半,直到gap小于1,停止调用。代码如下:

      ArrayList.prototype.shellSort = function () {
        let length = this.array.length
        let gap = Math.floor(length / 2)
        while (gap >= 1) {
          this.insertionSort(gap)
          gap = Math.floor(gap / 2)
        }
      }   

 

posted on 2021-06-22 12:47  springxxxx  阅读(55)  评论(0)    收藏  举报