[排序介紹] 插入排序 Insertion Sort

插入排序法(Insertion Sort)的概念有點像我們一張一張地整理撲克牌,拿出尚未排序的一張,放進已經排序好的排堆裡面。

首先來看 input 和 output:

Input:n 個元素的序列 \(\{a_1, a_2,\dots ,a_n\}\)

Output:一個已經排序好的序列 \(\{a_1′, a_2′,\dots ,a_n’\}\),其中 \(a_1′ \leq a_2′ \leq \dots \leq a_n’\)。

嗯,好像在講廢話,沒什麼特別的。

流程說明

首先,我們想排序的是這六位數字:2、5、3、6、1、4。

過程差不多是這樣:

一直重複以下動作,從第二個位置(index=1)開始一直到陣列結束(從 2 到 A 的長度)。先設定 key 是第 j 個位置(index=j-1),並且設定檢查項為第 j 個位置的前面,每次檢查完就往前一個位置,一直到第 1 個位置檢查結束(index 從 i -1 到 1)。

好的,前提如果清楚了,就可以開始排序流程了。每次都拿 key 往前對照已排序的部分,如果檢查項大於 key,檢查項則須往後移一格。若沒有大於 key,就不用動(也就是 i+1 的位置就是 key)。

用文字說明比較不好懂,不如直接看圖片或許會比較好想像。

圖片說明

※ 橘色底為目前的檢查項、藍色為 key、綠色打勾為已排序的部分。

首先,5 是 key(從 index=2 的位置開始),2是檢查項。因為 key 沒有比2還要大,所以可以直接放進去檢查項後面一格位置。

再來 key 是第三個位置的 3,檢查項是第三個位置的前一格(第二格,index=1),也就是5。因為檢查項5 大於 key,因此 5 需要往後移一格。

動作完成後,將檢查項的位置往前一格(第一格,index=0),也就是 2。2 沒有大於 key,因此不需要移動,key 就放入檢查項後面一格的位置。

再來 key 是第四個位置的 6,檢查項是第四個位置的前一格(第三格,index=2),也就是 5。5 沒有大於 key,因此不需要移動,6 就放入檢查項後面一格的位置。

再來 key 是第五個位置的 1,噢這項相當小,應該要移動相當多格了XD

  • 檢查項是第五個位置的前一格(第四格,index=3),也就是 6。檢查項 6 大於key,因此6需要往後移一格。
  • 檢查項的位置往前一格(第三格,index=2),也就是 5。檢查項 5 大於 key,因此 5 需要往後移一格。
  • 檢查項的位置往前一格(第二格,index=1),也就是 3。檢查項 3 大於 key 的 1,因此 3 需要往後移一格。
  • 檢查項的位置往前一格(第一格,index=0),也就是 2。檢查項 2 大於 key,因此2需要往後移一格。
  • 最後也就剩第一格的位置可以放入key了。

key 終於輪到最後一個數字了!最後的 key 是第六個位置的 4。

  • 檢查項是第六個位置的前一格(第五格),也就是 6。檢查項 6 大於 key,因此 6 需要往後移一格。
  • 再來檢查項是第五個位置的前一格(第四格),也就是 5。檢查項 5 大於key,因此 5 需要往後移一格。
  • 再來檢查項是第四個位置的前一格(第三格),也就是 3。檢查項 3 沒有大於key,因此3不需要移動,4可以放在檢查項後面一格的位置。

完成排序了!!!!基本上核心概念就是:指定 key 的值(從第二格開始),並從 key 的位置開始往前檢查,比 key 大就往後移一格,沒有移動就把 key 塞到適當位置。檢查完後 key 的 index 往後一格取值,重複前述步驟往前檢查。

已經有了圖像的概念,再來看虛擬碼應該會容易一些。

for j = 1 to A.length
  key = A[j]  //設定key
  i = j - 1  //開始從key的前一個位置往前檢查
  while i >= 0 and A[i] > key //目前檢查項大於key的話
    A[i+1] = A[i]  //把檢查項往後移一格
    i = i - 1      //index往前一格	
  A[i+1] = key  //檢查完之後,在目前跑到的index放入key

分析

分析氣泡排序的時間複雜度。最好的狀況是 \(O(n)\),也就是順序剛好都排好時(未進行任何 swap)。平均來說是 \(O(n^2)\),尤其是資料由大到小,完全相反,因此每次執行次數為 n-1 次、n-2 次……一直到 1 次。

\(\displaystyle (n-1) + (n-2) + \dots + 1 = \frac{n(n-1)}{2} = \frac{n^2-n}{2} \Rightarrow O(n^2)\)

實作

接著照上方 pseudo code 試著實作看看(C++)。

#include <vector>
using namespace std;

vector<int> insertionSort(vector<int> array) {
  for (int j = 1; j < array.size(); j++){
    int key = array[j];
    int i = j - 1;
    while (i >= 0 && array[i] > key){
      array[i+1] = array[i];
      i = i - 1;
    }
    array[i+1] = key;
  }
  return array;
}

讓我知道你在想什麼!

Picture of ALEX

ALEX

藍白拖愛好者,一事無成話偏多

Recent Posts

C++

NLP