希尔排序
我们还记得,插入排序的思路是:
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) } }
浙公网安备 33010602011771号