希尔排序
基本概念
希尔排序是一种插入排序的算法,它是对简单的插入排序进行改进后,更高效的版本。
特点是利用增量,将数组分成一组组子序列,然后对子序列进行插入排序。
由于增量是从大到小,逐次递减,所以也称为缩小增量排序。
具体步骤
初始数据为arr = [8,9,1,7,2,3,5,4,6,0];
初始增量设置为数组长度的一半,即flag = arr.length/2 = 5;
每次增量减少一半,直到小于1结束。
以5为增量:
- 第一步 下标为0 {8,3}
- 第二步 下标为1 {9,5}
- 第三步 下标为2 {1,4}
- 第四步 下标为3 {7,6}
- 第五步 下标为4 {2,0}
总共得到 五组{8,3} {9,5} {1,4} {7,6} {2,0}
对每一组进行直接插入排序,得到{3,8} {5,9} {1,4} {6,7} {0,2}
最终结果为 [3,5,1,6,0,8,9,4,7,2]
以2位增量:
- 第一步 下标为0 {3,1,0,9,7}
- 第二步 下标为1 {5,6,8,4,2}
总共得到 两组{3,1,0,9,7},{5,6,8,4,2}
对每一组进行直接插入排序,得到{0,1,3,7,9},{2,4,5,6,8}
最终结果为 [0,2,1,4,3,5,7,6,9,8]
以1为增量:
- 第一步{0,2,1,4,3,5,7,6,9,8}
- 进行直接插入排序[0,1,2,3,4,5,6,7,8,9]
- 下次增量为0结束。
代码实现
/**
* 希尔排序
*/
function shellSort(arr) {
// 用gap值对数组进行分组,然后对分组进行插入排序,直到gap值=1
// 首次gap值为Math.floor(arr.length / 2)
// 后面gap值为Math.floor(gap / 2)
let gap = Math.floor(arr.length / 2)
while (gap >= 1) {
// 通过gap分组
for (let k = 0; k < gap; k++) {
// 遍历每一组,并进行插入排序
// 插入排序的原理是,假设第一个数已经排好序,从第二个数开始
// 第一个数是k,第二个数是k+gap
for (let i = k + gap; i < arr.length; i = i + gap) {
let cur = i
// 注意不是j--哦,因为已经通过gap分组
for (let j = i - gap; j >= 0; j = j - gap) {
// 如果前一个数比当前数大,就交换位置,否则就插入
if (arr[j] > arr[cur]) {
let temp = arr[j]
arr[j] = arr[cur]
arr[cur] = temp
cur = j
} else {
// 插入就不继续循环了
break
}
}
}
}
// 继续缩小gap
gap = Math.floor(gap / 2)
}
return arr
}
console.log(shellSort([4, 5, 2, 3, 1, 0, -10, -3, -2]))