Skip to content

直接插入排序

核心思想

直接插入排序的核心思想:

  • 将待排序序列分为「已排序」和「未排序」两部分:初始时已排序部分只有第一个元素
  • 逐个插入:每次从未排序部分取出第一个元素,在已排序部分中从后向前扫描,找到合适位置插入
  • 有序区不断扩大:每插入一个元素,已排序部分长度加 1,直到全部元素有序

排序过程示意(升序):

初始:  [49] | 38  65  97  76  13  27
第1趟: [38  49] | 65  97  76  13  27
第2趟: [38  49  65] | 97  76  13  27
第3趟: [38  49  65  97] | 76  13  27
第4趟: [38  49  65  76  97] | 13  27
第5趟: [13  38  49  65  76  97] | 27
第6趟: [13  27  38  49  65  76  97]

其中 [] 内为已排序部分,| 右侧为未排序部分。

交互可视化

通过下方的交互动画,你可以逐步观察直接插入排序的执行过程:

加载可视化中...

操作详解

算法思路

关键步骤:

  1. 从第 2 个元素开始,将其作为待插入元素 temp
  2. 在已排序部分中从后向前扫描,将大于 temp 的元素依次后移
  3. 找到 temp 应插入的位置,将其放入
  4. 重复以上过程直到所有元素排完

不带哨兵的实现:

c
void InsertSort(int A[], int n) {
    int i, j, temp;
    for (i = 1; i < n; i++) {       // 从第2个元素开始
        if (A[i] < A[i - 1]) {      // 若当前元素小于前驱
            temp = A[i];             // 暂存待插入元素
            for (j = i - 1; j >= 0 && A[j] > temp; j--)
                A[j + 1] = A[j];    // 元素后移
            A[j + 1] = temp;         // 插入到正确位置
        }
    }
}

带哨兵的实现(⭐ 考研重点):

A[0] 作为哨兵,数据元素从 A[1] 开始存储。哨兵的作用是免去查找过程中每次循环都要判断 j >= 1 是否越界,从而简化边界条件、提高效率。

c
void InsertSort(int A[], int n) {
    int i, j;
    for (i = 2; i <= n; i++) {       // A[1]~A[n]存放元素
        if (A[i] < A[i - 1]) {
            A[0] = A[i];             // A[0]作为哨兵
            for (j = i - 1; A[0] < A[j]; j--)
                A[j + 1] = A[j];    // 元素后移
            A[j + 1] = A[0];         // 插入到正确位置
        }
    }
}

注意:使用哨兵时,A[0] 不存放实际数据,数组需多分配一个空间。

排序过程详解

以序列 [49, 38, 65, 97, 76, 13, 27] 为例,展示每一趟的操作:

趟数待插入元素比较与移动过程排序结果
13838 < 49,49 后移,38 插入位置 1[38, 49, 65, 97, 76, 13, 27]
26565 > 49,无需移动[38, 49, 65, 97, 76, 13, 27]
39797 > 65,无需移动[38, 49, 65, 97, 76, 13, 27]
47676 < 97,97 后移;76 > 65,插入[38, 49, 65, 76, 97, 13, 27]
513依次与 97、76、65、49、38 比较并后移[13, 38, 49, 65, 76, 97, 27]
627依次与 97、76、65、49、38 比较并后移;27 > 13[13, 27, 38, 49, 65, 76, 97]

每一趟排序后,前 i+1 个元素构成有序序列。共需 n-1 趟排序。

稳定性分析

直接插入排序是稳定的排序算法。

原因:在从后向前扫描已排序部分时,遇到与待插入元素相等的元素就会停止扫描,将待插入元素放在相等元素的后面。因此,相同关键字的元素在排序前后的相对顺序不会改变。

复杂度分析

指标复杂度说明
最好时间复杂度O(n)序列已有序,每趟只比较 1 次,不移动
最坏时间复杂度O(n²)序列逆序,每趟比较 i 次并移动 i+1 次
平均时间复杂度O(n²)平均比较和移动次数约为 n²/4
空间复杂度O(1)仅需常数级辅助空间(temp / 哨兵)

适用场景:直接插入排序在序列基本有序数据量较小时效率较高,是小规模排序的首选算法。

易错:直接插入排序在基本有序序列上的时间复杂度接近 O(n)(内层循环几乎不执行)。408 选择题经典问法:"对基本有序序列,以下哪种排序最高效?"——答案是直接插入排序,不是冒泡(虽然冒泡也是 O(n),但常数因子更大)。

易错:直接插入排序是稳定排序(相等元素比较时不交换,保持原有顺序)。

考研高频考点

  • ⭐ 哨兵的作用及带哨兵代码的手写(代码题/填空题高频)
  • ⭐ 最好/最坏/平均时间复杂度及对应的输入情况(选择题必考)
  • ⭐ 稳定性判断及原因说明(简答题/选择题高频)
  • ⭐ 给定序列写出每趟排序结果(选择题/填空题)
  • 与希尔排序的关系与对比(希尔排序是插入排序的改进)
  • 适用场景分析:基本有序 / 小规模数据时优于 O(n log n) 算法

相关知识

  • 折半插入排序——用折半查找减少比较次数的优化版本
  • 希尔排序——插入排序的增量版,突破 O(n^2) 瓶颈
  • 冒泡排序——同为 O(n^2) 的排序算法,适合与插入排序对比
  • 快速排序——小规模子序列常切换为插入排序来提速

真题练习

相关真题(6题)

2026Q9选择题2分

直接插入排序比较次数:初始序列越有序比较次数越少

2022Q11选择题2分

排序算法选择:数据大部分有序、元素少、O(1)空间、需稳定时选直接插入排序

2020Q11选择题2分

排序效率对比:有序数组上直接插入排序的比较次数最少

2017Q10选择题2分

排序算法效率对比:归并排序 vs 插入排序的时间复杂度优势

2012Q11选择题2分

插入排序比较次数:最好与最坏情况下比较次数的差异

2009Q10选择题2分

插入排序特征:第二趟后前三个元素有序的排序算法识别