五大经典排序算法:插入、希尔、冒泡、选择、堆排序全攻略

五大经典排序算法全攻略:插入、希尔、冒泡、选择、堆排序
(2026年面试/刷题/教学最实用版,带原理、动画思路、代码、复杂度、优缺点对比)

这五大算法是排序家族的入门基石,几乎所有大厂算法面试/数据结构课程都会反复考查。它们都是比较排序,且原地排序(除了极少数变体),空间大多O(1)。

一、五大算法速览对比表(背这个就够了)

排序算法时间复杂度(最好/平均/最坏)空间复杂度稳定性原地适用场景 / 特点面试常考点
冒泡O(n) / O(n²) / O(n²)O(1)稳定小数据、教学演示、几乎不用生产简单但低效
选择O(n²) / O(n²) / O(n²)O(1)不稳定小数据、辅助内存极少时交换次数最少(≈n次)
插入O(n) / O(n²) / O(n²)O(1)稳定近乎有序数据、在线排序、小数组实际比冒泡快2倍左右
希尔O(n log n) ~ O(n^{1.3}) / O(n²)O(1)不稳定中等规模数据、突破O(n²)的入门算法增量序列选择、gap优化
O(n log n) / O(n log n) / O(n log n)O(1)不稳定大数据、优先队列实现、TopK问题建堆O(n)、原地、不递归

稳定性:相同key的元素,排序前后相对位置不变 → 重要场景如多字段排序。

二、逐个拆解(原理 + 图解思路 + Python代码)

1. 冒泡排序(Bubble Sort)—— 最简单但最慢

原理:相邻比较 + 交换,不断把最大/最小“冒泡”到一端。
动画思路:像气泡上升,每轮把当前最大沉底。

def bubble_sort(arr):
    n = len(arr)
    for i in range(n):                  # 轮数
        swapped = False
        for j in range(0, n - i - 1):   # 每轮少比一次
            if arr[j] > arr[j + 1]:
                arr[j], arr[j + 1] = arr[j + 1], arr[j]
                swapped = True
        if not swapped:                 # 优化:已有序早停
            break
    return arr

优点:实现最简单、稳定
缺点:交换次数多(逆序时O(n²)次交换),实际最慢

2. 选择排序(Selection Sort)—— 交换次数最少

原理:每轮从未排序部分选出最小(或最大),放到已排序部分的末尾。
动画思路:像选国王,每轮找当前最小的“国王”放前面。

def selection_sort(arr):
    n = len(arr)
    for i in range(n):
        min_idx = i
        for j in range(i + 1, n):
            if arr[j] < arr[min_idx]:
                min_idx = j
        arr[i], arr[min_idx] = arr[min_idx], arr[i]  # 只交换一次
    return arr

优点:交换次数固定≈n次(比冒泡/插入少得多)
缺点:不稳定(跨大距离交换导致)

3. 插入排序(Insertion Sort)—— 最实用的O(n²)

原理:构建有序序列,把新元素插入到合适位置(从后往前挪动)。
动画思路:像打扑克摸牌,摸一张插到正确位置。

def insertion_sort(arr):
    for i in range(1, len(arr)):
        key = arr[i]
        j = i - 1
        while j >= 0 and arr[j] > key:
            arr[j + 1] = arr[j]      # 后移
            j -= 1
        arr[j + 1] = key             # 插入
    return arr

优点:近乎有序时接近O(n)、稳定、原地
缺点:逆序时最坏O(n²)比较+移动

为什么面试常说“插入比冒泡更好”?
插入平均移动/比较次数 ≈ n²/4,冒泡 ≈ n²/2;插入对近序数据极友好。

4. 希尔排序(Shell Sort)—— 插入排序的加强版

原理:分组插入排序,先大步长(gap)分组排序,逐步缩小gap到1。
动画思路:先粗排(让数组“更接近有序”),再精排。

def shell_sort(arr):
    n = len(arr)
    gap = n // 2
    while gap > 0:
        for i in range(gap, n):
            temp = arr[i]
            j = i
            while j >= gap and arr[j - gap] > temp:
                arr[j] = arr[j - gap]
                j -= gap
            arr[j] = temp
        gap //= 2                     # 经典gap/2,也可用Hibbard序列等
    return arr

优点:突破O(n²),实际性能很好(gap选择影响大)
缺点:不稳定、gap序列无理论最优

5. 堆排序(Heap Sort)—— 原地O(n log n)

原理:先建大顶堆(或小顶堆),然后反复把堆顶(最大)放到末尾,调整堆。
动画思路:先把数组“堆”起来(O(n)建堆!),然后像拔河一样拔最大值。

def heapify(arr, n, i):           # 向下调整
    largest = i
    l = 2 * i + 1
    r = 2 * i + 2
    if l < n and arr[l] > arr[largest]:
        largest = l
    if r < n and arr[r] > arr[largest]:
        largest = r
    if largest != i:
        arr[i], arr[largest] = arr[largest], arr[i]
        heapify(arr, n, largest)

def heap_sort(arr):
    n = len(arr)
    # 建堆(从最后一个非叶子节点开始)
    for i in range(n // 2 - 1, -1, -1):
        heapify(arr, n, i)
    # 排序
    for i in range(n - 1, 0, -1):
        arr[0], arr[i] = arr[i], arr[0]
        heapify(arr, i, 0)
    return arr

优点:最坏/平均都是O(n log n)、原地、不递归
缺点:不稳定、实际常数较大(比快排慢)

三、总结一句话建议

  • 小数据 / 近乎有序 / 需要稳定 → 插入排序(王者)
  • 中等数据 / 想突破O(n²) → 希尔排序(性价比之王)
  • 大数据 / 要保证O(n log n) → 堆排序(原地稳定选手)或快排(实际最快,但最坏O(n²))
  • 教学/面试手撕 → 插入 > 冒泡 > 选择 > 希尔 > 堆

你现在是在准备面试手撕代码,还是想深入某个算法的优化(如希尔gap序列、堆的建堆证明、插入的二分优化)?
或者想看这五个算法的动画演示链接 / 真实性能测试对比?告诉我,我继续给你针对性扩展!

文章已创建 4791

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部