「这是我参与2022首次更文挑战的第5天,活动详情查看:2022首次更文挑战」
希尔排序
介绍
希尔排序 这是十大排序算法里的基础排序,这个理解起来比 直接插入排序算法 有点难。
又称 缩小增量排序。它属于插入排序里面的,它比直接插入排序算法更优,是直接插入排序算法的改进版。是一种 非稳定 排序算法,不能用于链表。
为什么又称为 缩小增量排序,是因为它会优先比较距离较远的元素,然后依次缩减 间隔序列(增量),再进行插入排序。直到 间隔序列(增量) 为1时,进行最后一次直接插入排序,排序结束。
问题
我这里刚开始遇到希尔排序时,遇到的问题有两个
-
增量:希尔排序算法的关键 间隔序列的设定(增量)。它是是提前指定好?还是说动态的定义间隔序列?
-
奇偶数:网上大多数原数据的个数都是 偶数,来进行排序讲解的例子。但是如果原数据的个数是奇数的话,最后一个单的是如何处理的呢?处理方案是什么呢?
解决
-
首先我们先处理 间隔序列(增量)的问题
这里大部分的选择都是,(数据总长度 / 2) 然后,向下取整,得到的结果 继续/2,向下取整,直到间隔序列(增量)为1。
用代码表示就是
// increment 间隔序列(增量)值 for (let increment = Math.floor(len / 2); increment > 0; increment = Math.floor(gap / 2)) {} -
奇偶数 问题
通过对期画图演示,了解下来,奇偶数问题,其实是没有影响的,可以查看下面演示,即可知道为什么奇偶数没有影响。
演示
注意以下相同背景颜色为一组
-
初始化
原始数组
[10, 7, 6, 3, 0, 1, 4, 2, 5, 9, 8],总长度len = 11,为奇数。
-
第一次增量
第一次的增量
Math.floor(len / 2) = 5,数组分 6 组, 为[10,1],[7,4],[6,2],[3,5],[0,9]和[10,8]。这里可能会有人对最后一组有疑问,为什么是
[10,8],而不是[1,8]。因为我们是循环遍历依次执行,所以到最后一组的时候,1所在的位置的值已经变成了10。
-
第一次的排序结果:
[1, 4, 2, 3, 0, 8, 7, 6, 5, 9, 10] -
第二次增量
第二次的增量
Math.floor(5 / 2) = 2,数组分 2 组, 为[1,2,0,7,5,10],[4,3,8,6,9]。
- 第二次的排序结果:
[0, 3, 1, 4, 2, 6, 5, 8, 7, 9, 10]
- 第三次的增量
Math.floor(2 / 2) = 1,最终的排序结果:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
题目
-
排序数组-912
给你一个整数数组
nums,请你将该数组升序排列
代码
- 排序数组 912题
// shellSort const sortArray = (nums) => { const numsLength = nums.length // 10 for (let increment = Math.floor(numsLength / 2); increment > 0; increment = Math.floor(increment / 2)) { // 我们从第 increment 个开始,依次往后 for (let i = increment; i < numsLength; i++) { const current = nums[i] let j = i // 与间隔为 increment 的值 进行比对,也就是开始插入排序 while (j - increment >= 0 && current < nums[j - increment]) { nums[j] = nums[j - increment] j = j - increment } nums[j] = current } } return nums }
总结
希尔排序算法 比 直接插入排序算法 效率高的原因是:当刚开始元素很无序的时候,步长最大,所以插入排序的元素个数很少,速度很快;当元素基本有序了,步长很小,直接插入排序对于有序的序列效率很高。
注意:由于 希尔排序算法 的 不稳定性,所以 不能 用于 链表(因为链表不能随机访问)。