首页 / 算法动画 / 插入排序

插入排序动画

像整理手牌一样,把每个元素插到已排序区间的正确位置

时间复杂度 O(n²) 空间复杂度 O(1) 稳定
动画加载中…

算法原理

插入排序(Insertion Sort)就是整理手牌的过程:左手里的牌始终是有序的,每次从牌堆顶摸一张新牌,从右往左比较,把它插到正确的位置。对应到数组上,把序列分成「已排序前缀」和「未排序后缀」,逐个取未排序部分的第一个元素(记为 key),在已排序前缀里从后向前扫描,比 key 大的元素依次右移一格,腾出位置后把 key 放入。

对长度为 n 的序列,执行过程是:

  1. 第 1 轮:把 a[1] 作为 key 插入前缀 a[0..1]
  2. 第 2 轮:把 a[2] 作为 key 插入前缀 a[0..2]……
  3. 第 i 轮:扫描 a[i-1] → a[0],凡大于 key 的右移一格,遇到不大于 key 的位置(或到头部)就把 key 放下;前缀每轮增长一格,n-1 轮后整体有序。

动画怎么看

柱子颜色就是状态语言(页面右侧也有图例):

  • 绿色柱:已排序前缀 a[0..i],从左往右生长;
  • 金色柱:当前正在与 key 比较的候选元素 a[j-1]
  • 红色柱:比 key 大、正在右移的元素;
  • 蓝色柱:尚未处理的元素。

动画下方有一行实时解说(如 a[0] = 38 > key,右移到 a[1]key = 25 插入 a[2] 就位),结束时汇总总比较次数与右移次数。可以注意观察:比较次数与移动次数是分开计数的——右移的总次数正是序列「逆序对」数量的量级,越接近有序的输入,插入排序越快。

复杂度分析

项目复杂度说明
平均/最坏时间O(n²)逆序输入时,第 i 轮要比较、右移 i 次
最好时间O(n)序列本身有序时,每轮只比较一次即就位
空间O(1)只需 key 一个辅助变量,原地排序
稳定性稳定只有「大于 key 才右移」,相等元素不会跨越,相对次序保持

C++ 参考代码

#include <iostream>
#include <vector>
using namespace std;

// 插入排序:把 a[i] 插入已排序的 a[0..i)
void insertionSort(vector<int>& a) {
    int n = a.size();
    for (int i = 1; i < n; i++) {
        int key = a[i];          // 摸出的新牌
        int j = i;
        while (j > 0 && a[j - 1] > key) {
            a[j] = a[j - 1];     // 比 key 大的右移一格
            j--;
        }
        a[j] = key;              // 放入空出的位置
    }
}

int main() {
    vector<int> a = {5, 2, 9, 1, 7, 3, 8, 4};
    insertionSort(a);
    for (int x : a) cout << x << ' ';   // 输出:1 2 3 4 5 7 8 9
    cout << endl;
    return 0;
}

什么时候用插入排序

插入排序平均 O(n²),大数据量下不如快速排序、归并排序。但它有两大实用价值:一是对「基本有序」的数据接近 O(n),常作为 O(n log n) 排序(如 std::sort 的小区间策略、TimSort)的底层配件;二是实现简单、稳定、原地,是理解「增量构造解」思想的入门范例。CSP-J 阶段的「扑克牌理牌」「链表插入」等题都是它的变体。