首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

經典排序算法系列(二):插入排序、希爾排序與二分插入優化

     編輯:關於C語言

前言:插入類排序的「構建有序區」思想

插入排序族核心:維護一個已有序的前綴區間,逐個將後續元素插入合適位置。本文涵蓋直接插入、二分插入(折半插入)、希爾排序(縮小增量排序),從原理、代碼、複雜度、適用場景全方位解析。

一、直接插入排序

1. 算法邏輯

外層遍歷 i = 1 ~ n-1,內層將 arr[i] 向左比較位移,直到找到 arr[j] <= key,插入 j+1。

2. 標準實現


void insertSort(int arr[], int n) {
    for (int i = 1; i < n; ++i) {
        int key = arr[i];
        int j = i - 1;
        while (j >= 0 && arr[j] > key) {
            arr[j + 1] = arr[j];
            --j;
        }
        arr[j + 1] = key;
    }
}

3. 屬性分析

屬性值
時間複雜度最好 O(n)(有序)、平均/最壞 O(n²)
空間複雜度O(1)
穩定性穩定
適應性強(近乎有序時極快)
適用場景小規模 (n<50)、近乎有序、在線排序(流式數據)

二、二分插入排序——優化查找位置

1. 改進點

內層線性查找插入位置 → 二分查找,比較次數從 O(n) 降為 O(log n);但元素位移仍需 O(n),總體時間複雜度仍為 O(n²),僅減少比較操作。

2. 實現


void binaryInsertSort(int arr[], int n) {
    for (int i = 1; i < n; ++i) {
        int key = arr[i];
        int lo = 0, hi = i - 1;
        while (lo <= hi) {
            int mid = (lo + hi) / 2;
            if (arr[mid] > key) hi = mid - 1;
            else lo = mid + 1;
        }
        // lo 為插入位置
        for (int j = i - 1; j >= lo; --j) arr[j + 1] = arr[j];
        arr[lo] = key;
    }
}

三、希爾排序——插入排序的「跨越式」升級

1. 核心思想:分組 + 插入 + 遞減增量

  1. 選擇增量序列 gap = n/2, n/4, ..., 1(原文採用)。
  2. 對每個 gap,將數組分為 gap 組(下標模 gap 相同),組內直接插入排序。
  3. 最後 gap=1 即普通插入排序,但此時數組已基本有序,極快。

2. 增量序列選擇影響巨大

序列公式平均複雜度備註
Shell 原版n/2^kO(n²)最差
Hibbard2^k - 1O(n^{3/2})
Sedgewick9*4^k - 9*2^k + 1 或 4^k - 3*2^k + 1O(n^{4/3})工程常用
Pratt2^p * 3^qO(n log² n)最佳理論

3. 實現(Shell 原版增量)


void shellSort(int arr[], int n) {
    for (int gap = n / 2; gap > 0; gap /= 2) {
        for (int i = gap; i < n; ++i) {
            int key = arr[i];
            int j = i - gap;
            while (j >= 0 && arr[j] > key) {
                arr[j + gap] = arr[j];
                j -= gap;
            }
            arr[j + gap] = key;
        }
    }
}

4. 屬性

屬性值
時間複雜度依增量序列:O(n²) ~ O(n log² n)
空間複雜度O(1)
穩定性不穩定(跨組交換破壞相對序)
適用場景中等規模 (n ~ 1000~10000)、嵌入式無法遞歸/棧受限環境

四、三者對比與選型指南

算法比較次數移動次數穩定最佳場景
直接插入O(n²)O(n²)✅極小/近乎有序
二分插入O(n log n)O(n²)✅比較昂貴(如大對象)、近乎有序
希爾排序O(n^{1.5})~O(n^{1.5})~❌中等規模、原地、無遞歸

五、工程建議

  1. 小數組切換閾值:快排/歸併遞歸到底時(n < 16)改用直接插入。
  2. 希爾增量用 Sedgewick:實測比 Shell 原版快 2-3 倍,代碼僅增量序列不同。
  3. 二分插入適用於「比較成本高」:如字串、大結構體排序;整數排序現代 CPU 分支預測極強,線性查找未必慢。

總結

插入類排序以「構建有序區」為核心,直接插入簡洁穩定,二分插入優化比較,希爾排序通過分組跳躍打破 O(n²) 瓶頸。理解增量序列對希爾排序的決定性影響,是從「會用」到「精通」的分水嶺。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved