希尔排序算法详解:原理、实现与优化
一、算法概述
希尔排序(Shell Sort)是 Donald Shell 于 1959 年提出的一种改进的插入排序算法,也被称为缩小增量排序。它的核心在于将原始数组分解为若干个子序列进行插入排序,随着增量逐渐减小,最终对整个数组进行一次标准的插入排序。
基本特性
- 时间复杂度:取决于增量序列的选择,通常在 O(n^1.3) 到 O(n^2) 之间
- 空间复杂度:O(1),属于原地排序
- 稳定性:不稳定排序算法
- 适用场景:中等规模数据,特别是部分有序的数据集
二、算法原理详解
核心思想
理解希尔排序,关键在于把握以下三点:
- 分组插入排序:按照当前的增量 gap 将数组划分为若干子序列,对每个子序列分别执行插入排序。
- 逐步缩小增量:每次迭代后缩小 gap 值,让元素移动的距离变短,但整体有序性增强。
- 最终插入排序:当 gap 缩减为 1 时,相当于对整个数组进行一次标准的插入排序,此时数组已接近有序,效率极高。
增量序列选择
增量序列的选择直接影响算法性能,常用的有以下几种:
- Shell 原始序列:gap = n/2, n/4, …, 1
- Hibbard 序列:1, 3, 7, …, 2^k - 1
- Sedgewick 序列:1, 5, 19, 41, 109, …
三、算法执行流程演示
我们以数组 [8, 9, 1, 7, 2, 3, 5, 4, 6, 0] 为例,直观地看一遍数据是如何流动的。
初始状态
┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
│ 8 │ 9 │ 1 │ 7 │ 2 │ 3 │ 5 │ 4 │ 6 │ 0 │
└───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
第一轮:gap=5
此时将数组分为 5 组:(8,3), (9,5), (1,4), (7,6), (2,0)。
分组示意图:
┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
│ 8 │ │ │ │ │ 3 │ │ │ │ │ → (8,3)
│ │ 9 │ │ │ │ 5 │ │ │ │ │ → (9,5)
│ │ │ 1 │ │ │ │ 4 │ │ │ │ → (1,4)
│ │ │ │ 7 │ │ │ │ 6 │ │ │ → (7,6)
│ │ │ │ │ │ │ │ │ │ │ → (,)
└───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
排序后结果:
┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
│ │ │ │ │ │ │ │ │ │ │
└───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘


