本篇將為大家介紹插入排序 (Insertion Sort) 的原理、虛擬碼、程式碼與時間複雜度分析。
插入排序
概念有點類似平常玩的撲克牌。當莊家發牌時,玩家拿到第一張牌、接著拿到第二張牌的時候,就會先把兩張作比較排序好。
接下來第三張牌接著插入這堆已經排序好的排組,接著同理。直到撲克牌發完的時候,手上的撲克牌也已經依照點數大小排序好了。

虛擬碼
for j = 2 to A.length do //A為此堆資料的陣列
data = A[j] //data為要插入的資料
i = j-1
while i > 0 and A[i] > data do
A[i+1] = A[i]; //若新插入的資料比較小,就把已經排序好的原資料向後移
i = i-1; //繼續向前檢查,直到新插入資料比較大為止
end while
A[j+1] = data; //最後將空下來的位置讓給新插入的資料
end for
程式碼
i = 2 開始,做 n-1 個回合──將第 i 筆資料插入前面 i-1 筆已排序好的資料,形成 n 筆排序好的資料。
原先想法:
- insert(list[], data, n) 作為副程式
- insort(list[], n) 作為主程式
#include <stdio.h>
int insert(int poker[], int card, int n) //把card插入前第0~n筆已排序好的資料
{
int j = n;
while(card < poker[j])
{
poker[j+1] = poker[j];
j--;
}
poker[j+1] = card;
return 0;
}
int insort(int poker[], int count) //排序第poker[1]到poker[count]筆資料
{
int i;
for(i = 2; i<=count; i++)
{
insert(poker, poker[i], i-1);
}
printf("Numbers Sorted: ");
for(i = 1; i<=count; i++)
{
printf("%d ", poker[i]);
}
printf("\n");
return 0;
}
int main()
{
int count;
scanf("%d", &count);
int poker[count];
poker[0] = -1000000;
int i;
printf("Numbers to be sorted: "); //印出待排序數字
for(i = 1; i<=count; i++)
{
scanf("%d", &poker[i]);
printf("%d ", poker[i]);
}
printf("\n");
insort(poker, count);
return 0;
}

其他的寫法:這個實現方式比較接近虛擬碼
從第二個資料開始,如果第二個資料比第一個資料大,順序就維持不變;否則將第一個資料往後移動,然後將第一個資料空下來的位置讓給第二個資料。
此時第一和第二個資料就由小到大排序完成。
同理,依序移動資料直到第 n 筆資料都排序完成。
#include <stdio.h>
int insertion_sort(int poker[], int n){
int i, j, card;
for(i = 1; i < n; i++){ //從第二張牌開始跟前面的撲克牌比大小
card = poker[i];
for(j = i-1; j>=0 && card<poker[j]; j--){ //把card插入前面排序好的撲克牌
poker[j+1] = poker[j];
}
poker[j+1] = card;
}
};
int main(){
int count, i;
scanf("%d", &count);
int poker[count];
for(i = 0; i < count; i++){
scanf("%d", &poker[i]);
}
printf("Numbers to be sorted: ");
for(i = 0; i<count; i++){
printf("%d ", poker[i]);
}
insertion_sort(poker, count);
printf("\n");
printf("Numbers Sorted: ");
for(i = 0; i<count; i++){
printf("%d ", poker[i]);
}
return 0;
}

時間複雜度
1. Best Case: O(n)
若 input data 剛好是由小到大的方式給予,每一回合只需比較一次,即可決定好要插入 data 的正確位置。
又共做了 n-1 回合,故總共比較 n-1 次即可完成 sort。
如果利用 Recursive Time Function 來解時間複雜度,同樣會得到 O(n) 的結果:
T(n) = T(n-1)+1, T(1) = 0
----------------------------------
T(n) = T(n-1)+1
= T(n-2)+2
= ...
= T(1)+(n-1) //帶入T(1) = 0
= n-1
=> O(n)
2. Worst Case: O(n2)
若 input data 剛好是反序由小到大給予。
input: n, n-1, n-2, ... , 2, 1 比較次數
------------------------------------------------------
Pass 1: (n-1), (n), n-2, ... 1 次
Pass 2: (n-2), (n-1), (n), n-3, ... 2 次
Pass 3: (n-3), (n-2), (n-1), (n), n-4, ... 3 次
...
Pass (n-1): (n-1) 次
Total = 1 + 2 + 3 + ... + (n-1)
= n(n-1)/2 次比較
=>O(n^2)
如果利用 Recursive Time Function 來解時間複雜度,同樣會得到 O(n2) 的結果:
T(n) = T(n-1)+(n-1), T(1) = 0
//n-1代表第n筆data插入之最多比較次數
----------------------------------
T(n) = T(n-1)+(n-1)
= T(n-2)+(n-2)+(n-1)
= ...
= T(1)+1+...+(n-1) //帶入T(1) = 0
= 1+2+...+(n-1)
= n(n-1)/2
=> O(n^2)
3. Average Case: O(n2)
T(n) = T(n-1)+(n/2), T(1) = 0
//n/2代表第n筆data插入之平均比較次數
----------------------------------
T(n) = T(n-1)+(n/2)
= T(n-2)+1/2[(n-1)+n]
= ...
= T(1)+1/2[2+...+n] //帶入T(1) = 0
= 1/2*{(n+2)(n-1)/2}
=> O(n^2)










