首页/数据结构/07-sorting/直接插入排序 🔗 在 Obsidian 中打开
数据结构 · 07-sorting

直接插入排序

难度 ★★重要度 ★★★★ 考查频率 高题型 算法 / 综合应用 数据结构/排序插入排序内排序
速查
将未排序部分的首个元素逐个与已排序部分比较并后移,插入正确位置。最好 $O(n)$(已序),最坏 / 平均 $O(n^2)$稳定、原地,是希尔排序的基础,适合基本有序的小规模数据。

速查

项目
核心思想将待排序元素插入到已排序子序列的正确位置
最好时间$O(n)$(已有序,只比较不移动)
最坏时间$O(n^2)$(逆序)
平均时间$O(n^2)$
空间$O(1)$
稳定性✅ 稳定
适用场景基本有序的小规模数据

核心概念

直接插入排序是最基本的插入排序算法。它将数组分为已排序未排序两部分,每次从未排序部分取出第一个元素,插入到已排序部分的正确位置。

核心思想:从第 2 个元素开始,将当前元素与已排序部分从后往前逐个比较,找到合适位置后插入。

算法步骤

  1. 从 $i=2$ 到 n,依次处理每个元素
  2. 将 $A[i]$ 暂存到哨兵 $A[0]$
  3. 从已排序的末尾开始,向前扫描,将大于 $A[0]$ 的元素后移一位
  4. 将 $A[0]$ 插入到空出的位置

代码实现

void InsertSort(int A[], int n) {
    int i, j;
    for (i = 2; i <= n; i++) {        // 从第2个元素开始
        if (A[i] < A[i-1]) {           // 需要插入
            A[0] = A[i];               // 暂存到哨兵
            for (j = i-1; A[0] < A[j]; j--)  // 从后往前找
                A[j+1] = A[j];         // 后移
            A[j+1] = A[0];             // 插入
        }
    }
}

手算示例

49, 38, 65, 97, 76, 13, 27, 49* 排序:

初始:  [49] 38 65 97 76 13 27 49*
i=2:   [38 49] 65 97 76 13 27 49*    (38插入49前)
i=3:   [38 49 65] 97 76 13 27 49*    (65已在正确位置)
i=4:   [38 49 65 97] 76 13 27 49*    (97已在正确位置)
i=5:   [38 49 65 76 97] 13 27 49*    (76插入65和97之间)
i=6:   [13 38 49 65 76 97] 27 49*    (13插入最前)
i=7:   [13 27 38 49 65 76 97] 49*    (27插入13和38之间)
i=8:   [13 27 38 49 49* 65 76 97]    (49*插入49和65之间)

关键性质

性质说明
最好时间$O(n)$,序列已有序,每轮只比较 1 次
最坏时间$O(n^2)$,序列逆序,每轮比较 i 次 + 移动 i-1 次
平均时间$O(n^2)$,约 $n^2/4$ 次比较和移动
空间复杂度$O(1)$,原地排序
稳定性稳定(相等元素不交换)
适用性顺序表和链表均可
趟数n-1 趟

常见考法

考法 1:手动模拟排序过程逐趟写出结果。
考法 2:求比较 / 移动次数最好 n-1 次比较,最坏约 $n^2/2$ 次。
考法 3:判断稳定性稳定,相等元素不改变相对位置。
考法 4:适用条件基本有序 + 数据量小。
考法 5:与其他插入排序对比比折半插入排序比较次数多,但思想更基础。

易错点

注意
  1. ⚠️ 从第 2 个元素(下标 2)开始,不是从第 1 个。
  2. ⚠️ 哨兵 $A[0]$ 的作用是暂存 + 防止越界,不是元素本身。
  3. ⚠️ 已有序时只需 n-1 次比较,0 次移动(最好 $O(n)$)。
  4. ⚠️ 直接插入排序是稳定的。
  5. ⚠️ 一趟排序后,前 i 个元素有序,但不一定是最小的 i 个。

核心结论

  1. 平均 $O(n^2)$,最好 $O(n)$(已有序),最坏 $O(n^2)$(逆序)。
  2. 稳定排序,原地排序。
  3. 适合基本有序的小规模数据。
  4. 是希尔排序的基础。
  5. 408 考试中需能手动模拟每趟结果并统计比较 / 移动次数。

记忆卡片

时间复杂度?
最好 $O(n)$,最坏 $O(n^2)$,平均 $O(n^2)$。
稳定吗?
稳定。相等元素不交换相对位置。
最好情况的条件?
序列已有序,每轮只比较 1 次不移动。
哨兵 A[0] 的作用?
暂存待插入元素 + 防止数组下标越界。
适合什么场景?
基本有序、数据量小的场景。
和希尔排序的关系?
直接插入排序是希尔排序的基础(希尔 = 分组直接插入)。

交互动画 · 插入 76 到已排序前缀

已排序前缀 A[0..3] = [38, 49, 65, 97],将 76 逐个比较插入 76 待插入 380 491 652 973 4 浅蓝 = 正在比较的元素(>76 则后移);橙格 = 最终插入位置;97 后移一位
点击「演示插入 76」查看逐个比较、后移、插入的过程
比较 2 次(97、65),移动 1 次(97 后移)

相关知识点

binary-insertion-sort shell-sort insertion-sort