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

直接插入排序演算法:C++ 實作與效能分析

     編輯:關於C語言

前言:簡單但實用的排序演算法

直接插入排序是原地、穩定、線性空間的排序演算法。雖然平均時間複雜度為 O(n²),但對小規模資料、近乎有序、或線上排序 (資料逐筆到達) 場景極具優勢。本文提供標準 C++ 實作、效能特性分析與優化變體。

核心演算法邏輯

  1. 將陣列分為「已排序區間」與「未排序區間」
  2. 初始:已排序區間僅含第一個元素
  3. 每輪從未排序區間取第一個元素,插入已排序區間的適當位置
  4. 重複直到未排序區間為空

標準 C++ 實作

#include <iostream>
#include <vector>

void insertion_sort(std::vector<int>& arr) {
    const int n = arr.size();
    for (int i = 1; i < n; ++i) {
        int key = arr[i];           // 待插入元素
        int j = i - 1;
        
        // 從右向左掃描已排序區間,將大於 key 的元素右移
        while (j >= 0 && arr[j] > key) {
            arr[j + 1] = arr[j];
            --j;
        }
        arr[j + 1] = key;           // 插入正確位置
    }
}

// 通用版本:支援任意型別與自訂比較
template <typename RandomIt, typename Compare = std::less<>>
void insertion_sort(RandomIt first, RandomIt last, Compare comp = {}) {
    for (auto it = first + 1; it != last; ++it) {
        auto key = *it;
        auto j = it;
        while (j != first && comp(key, *(j - 1))) {
            *j = *(j - 1);
            --j;
        }
        *j = key;
    }
}

完整可執行範例

#include <iostream>
#include <vector>

void print_array(const std::vector<int>& arr) {
    for (int v : arr) std::cout << v << ' ';
    std::cout << '\n';
}

int main() {
    std::vector<int> arr = {7, 3, 5, 8, 9, 1, 2, 4, 6};
    std::cout << "Before: "; print_array(arr);
    
    insertion_sort(arr);
    
    std::cout << "After:  "; print_array(arr);
    return 0;
}

/* 輸出:
Before: 7 3 5 8 9 1 2 4 6
After:  1 2 3 4 5 6 7 8 9
*/

效能特性分析

指標數值說明
最佳時間複雜度O(n)輸入已排序,內層迴圈零執行
平均時間複雜度O(n²)隨機輸入
最差時間複雜度O(n²)輸入逆序,每輪需掃描整個已排序區間
空間複雜度O(1)原地排序,僅需常數額外空間
穩定性穩定相等元素相對順序不變
適應性高近乎有序時極快

優化變體

1. 二分搜尋插入點 (Binary Insertion Sort)

將線性掃描改為二分搜尋,比較次數從 O(n) 降為 O(log n),但移動次數仍為 O(n²),總體複雜度不變,適合「比較昂貴、移動廉價」的型別。

template <typename RandomIt, typename Compare = std::less<>>
void binary_insertion_sort(RandomIt first, RandomIt last, Compare comp = {}) {
    for (auto it = first + 1; it != last; ++it) {
        auto key = *it;
        // 在 [first, it) 範圍二分搜尋插入點
        auto pos = std::lower_bound(first, it, key, comp);
        // 將 [pos, it) 右移一位
        std::move_backward(pos, it, it + 1);
        *pos = key;
    }
}

2. 哨兵優化 (減少邊界檢查)


void insertion_sort_sentinel(int* arr, int n) {
    for (int i = 1; i < n; ++i) {
        if (arr[i] < arr[i-1]) {
            int key = arr[i];
            int j = i - 1;
            arr[0] = key;  // 哨兵位置
            while (key < arr[j]) {
                arr[j+1] = arr[j];
                --j;
            }
            arr[j+1] = key;
        }
    }
}

3. Shell Sort (希爾排序) — 進階改良

分組插入排序,縮小增量序列,平均複雜度可達 O(n^1.3) ~ O(n^1.5),是插入排序的實用化擴展。

實務應用場景

  • 小陣列 (n < 50):實際執行速度常快於快速排序/合併排序 (無遞迴開銷、快取友好)
  • 近乎有序資料:幾乎線性時間
  • 線上排序:資料流逐筆到達,需即時維持有序
  • 混合排序基礎:std::sort 實作常在小區間切換至插入排序 (如 GCC libstdc++ 閾值 16)

與其他 O(n²) 排序比較

演算法穩定最佳情況適應性實務表現
插入排序✓O(n)高小/近乎有序最佳
氣泡排序✓O(n)中教學用,實務較差
選擇排序✗O(n²)無交換次數最少 (O(n))

結語

直接插入排序雖非大規模排序首選,但其簡單、穩定、適應性強、零額外空間的特性,使其在特定場景 (小陣列、近乎有序、線上排序、混合排序基礎組件) 具有不可替代的價值。掌握其變體 (二分插入、希爾排序) 並理解標準庫如何利用它,是演算法工程師的基本功。

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