希尔排序(Shell Sort)

希尔排序的本质,是先用大步长把明显错位的元素提前搬近,再让最后一轮插入排序轻装上阵。

定义

希尔排序是插入排序的改进版本,也称为缩小增量排序。它通过比较相距一定间隔的元素来工作,逐步缩小间隔,最后间隔为1时就是普通插入排序。

核心思路

  1. 选择一个增量序列 t₁, t₂, …, tₖ,其中 tᵢ > tⱼ (i < j),tₖ = 1
  2. 按增量序列个数k,对序列进行k轮排序
  3. 每轮采用插入排序,间隔为当前增量
  4. 增量逐渐减小,最后一轮增量为1
原数组: [8, 9, 1, 7, 2, 3, 5, 4, 6, 0]

gap=5: 将数组分为5组
[8, 3] [9, 5] [1, 4] [7, 6] [2, 0]
排序后: [3, 5, 1, 6, 0, 8, 9, 4, 7, 2]

gap=2: 将数组分为2组
[3, 1, 0, 9, 7] [5, 6, 8, 4, 2]
排序后: [0, 2, 1, 4, 3, 5, 6, 7, 8, 9]

gap=1: 普通插入排序
最终: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

为什么它比插入排序快

普通插入排序一次只能把元素往前挪一小步。
希尔排序先用较大的 gap 做“粗调”,快速减少逆序对,再用较小的 gap 做“细调”,最后 gap = 1 时,数组通常已经接近有序了。

复杂度分析

指标复杂度说明
最好时间O(n log n)取决于增量序列
平均时间O(n^1.3)经验值,取决于增量序列
最坏时间O(n²)最差情况
空间复杂度O(1)原地排序
稳定性❌ 不稳定跨距离的交换破坏稳定性

注意:希尔排序的复杂度高度依赖于增量序列的选择。

Go 代码

Go 实现

package main
 
import "fmt"
 
func shellSort(arr []int) {
    n := len(arr)
 
    // 初始增量为n/2,逐步减半
    for gap := n / 2; gap > 0; gap /= 2 {
        // 对每个增量进行插入排序
        for i := gap; i < n; i++ {
            temp := arr[i]
            j := i
 
            for j >= gap && arr[j-gap] > temp {
                arr[j] = arr[j-gap]
                j -= gap
            }
 
            arr[j] = temp
        }
    }
}
 
func main() {
    arr := []int{8, 9, 1, 7, 2, 3, 5, 4, 6, 0}
 
    fmt.Println("原始数组:", arr)
    shellSort(arr)
    fmt.Println("排序后:", arr)
}

易错点

希尔排序最容易被写成“只是把插入排序套了个壳”,但关键其实在增量设计。

  • gap 序列不同,性能差异会很大。
  • 每一轮不是简单分组后单独排序,而是做“按 gap 取样的插入排序”。
  • 它不稳定,因为远距离移动会打乱相等元素次序。
  • 希尔排序适合中等规模数据,但不是面试里最核心的排序模板。

增量序列详解

经典题目

基础应用

  • 排序数组 - LeetCode 912
  • 实现不同增量序列的希尔排序

增量序列研究

  • 比较不同增量序列的性能
  • 找到最优增量序列
  • 证明希尔排序的时间复杂度

优缺点

优点

  • ✅ 比插入排序快很多
  • ✅ 原地排序 O(1) 空间
  • ✅ 实现简单
  • ✅ 对中等规模数据效率高
  • ✅ 自适应:对部分有序数据性能好

缺点

  • ❌ 不稳定
  • ❌ 复杂度分析困难
  • ❌ 性能依赖增量序列
  • ❌ 不如 O(n log n) 的算法

应用场景

  1. 中等规模数据:数据量在几千到几万
  2. 部分有序数据:数据基本有序
  3. 嵌入式系统:内存受限但需要比插入排序快
  4. 教学:展示算法改进思想

希尔排序的改进思想

希尔排序展示了如何改进简单算法:

  1. 插入排序的问题:每次只能移动一位,效率低
  2. 希尔的改进:先做”粗调”(大间隔),再做”细调”(小间隔)
  3. 预排序思想:通过预处理使数据”更有序”,加速最终排序

希尔排序 vs 插入排序

特性希尔排序插入排序
时间复杂度O(n^1.3) ~ O(n²)O(n²)
最好情况O(n log n)O(n)
稳定性不稳定稳定
实现难度中等简单
适用场景中等数据小数据/几乎有序

为什么希尔排序有效

  1. 减少逆序对:大间隔交换能快速减少逆序对数量
  2. 利用插入排序特性:插入排序对几乎有序的数据很快
  3. 预处理思想:先粗后细,逐步优化

相关主题


返回:排序算法 | 算法学习导航