跳转至

插入排序

本頁面將簡要介紹插入排序。

定義

插入排序(英語:Insertion sort)是一種簡單直觀的排序算法。它的工作原理為將待排列元素劃分為「已排序」和「未排序」兩部分,每次從「未排序的」元素中選擇一個插入到「已排序的」元素中的正確位置。

一個與插入排序相同的操作是打撲克牌時,從牌桌上抓一張牌,按牌面大小插到手牌後,再抓下一張牌。

insertion sort animate example

性質

穩定性

插入排序是一種穩定的排序算法。

時間複雜度

插入排序的最優時間複雜度為 \(O(n)\),在數列幾乎有序時效率很高。

插入排序的最壞時間複雜度和平均時間複雜度都為 \(O(n^2)\)

代碼實現

偽代碼

\[ \begin{array}{ll} 1 & \textbf{Input. } \text{An array } A \text{ consisting of }n\text{ elements.} \\ 2 & \textbf{Output. } A\text{ will be sorted in nondecreasing order stably.} \\ 3 & \textbf{Method. } \\ 4 & \textbf{for } i\gets 2\textbf{ to }n\\ 5 & \qquad key\gets A[i]\\ 6 & \qquad j\gets i-1\\ 7 & \qquad\textbf{while }j>0\textbf{ and }A[j]>key\\ 8 & \qquad\qquad A[j + 1]\gets A[j]\\ 9 & \qquad\qquad j\gets j - 1\\ 10 & \qquad A[j + 1]\gets key \end{array} \]
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
void insertion_sort(int arr[], int len) {
  for (int i = 1; i < len; ++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;
  }
}
1
2
3
4
5
6
7
8
def insertion_sort(arr, n):
    for i in range(1, n):
        key = arr[i]
        j = i - 1
        while j >= 0 and arr[j] > key:
            arr[j + 1] = arr[j]
            j = j - 1
        arr[j + 1] = key

折半插入排序

插入排序還可以通過二分算法優化性能,在排序元素數量較多時優化的效果比較明顯。

時間複雜度

折半插入排序與直接插入排序的基本思想是一致的,折半插入排序僅對插入排序時間複雜度中的常數進行了優化,所以優化後的時間複雜度仍然不變。

代碼實現

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
void insertion_sort(int arr[], int len) {
  if (len < 2) return;
  for (int i = 1; i != len; ++i) {
    int key = arr[i];
    auto index = upper_bound(arr, arr + i, key) - arr;
    // 使用 memmove 移動元素,比使用 for 循環速度更快,時間複雜度仍為 O(n)
    memmove(arr + index + 1, arr + index, (i - index) * sizeof(int));
    arr[index] = key;
  }
}