希尔排序是快排的一个变种,是首个突破 O(n2) 的排序算法。但是为什么说他快,看了一些知乎上的解释,这是一种实现简单,但是证明很难的算法。要用到很多数学概念,这里就算了。
算法说明:
- 取一个固定的步长(通常为待排数组长度的一半), 将数组分组,进行插入排序。
- 这里的分组并不是对半分,举例如下:假设有数组 [0, 1, 2, 3, 4, 5, 6, 7] 取步长 4,则 0,4 为一组,1,5为一组依次类推
- 分组后的排序,因为只有两个数比较,我也看到有直接用比较之后交换的,不一定是插入排序
- 将固定步长取半重复之前的运算规则
- 直到排序完步长为 1 的情况,排序结束
时间复杂度:
平均和最好: O(nlongn)
最坏: O(n2)
实现
说实话,道理我都懂,但是在看 Java 版本的希尔排序实现的时候,我看是看了半天,加上搜索视频教程和本地 debug 才理解下来的,他别是在这个交替进行的点,奇数个元素分组规则上,卡了挺久的。
1 | public class ShellSort { |
细节分析
以 [84, 32, 55, 3, 57, 68, 75, 71, 12, 43, 50] 为例子分析
第一次分组,对半分,由于元素格式 11 个,步长 5,将整个数组分为了五组
num | elements |
---|---|
1 | 84, 68, 50 |
2 | 32, 75 |
3 | 55, 71 |
4 | 3, 12 |
5 | 57, 43 |
我一开始以为代码实现的时候会先将 1 组中的各个元素抽出来,然后做一次插入排序,然后进行下第二组排序,一次类推。但实际上,在实现过程中,他会先将一组中第1,2 个元素用插入排序排完,然后直接跳到第二组,对1,2号元素排序,依次类推。等五个组的1,2 号元素都排完了,再回到第一组,对3号元素进行插入排序