基礎排序:O(n²) 排序演算法#
基礎排序演算法時間複雜度為 O(n²),適用於小規模資料。雖然效率不高,但實作簡單,是學習排序的起點。
核心概念#
有序度與逆序度#
- 有序度:陣列中有序元素對的數量,滿足
a[i] <= a[j]且i < j - 滿有序度:完全有序時的有序度 =
n*(n-1)/2 - 逆序度 = 滿有序度 - 有序度
排序的本質就是增加有序度、減少逆序度,直到達到滿有序度。
冒泡排序 (Bubble Sort)#
每次比較相鄰元素,將較大者「冒泡」到右側。
| 特性 | 說明 |
|---|---|
| 時間複雜度 | 最好 O(n)、最壞/平均 O(n²) |
| 空間複雜度 | O(1),原地排序 |
| 穩定性 | 穩定 |
冒泡排序程式碼
def bubble_sort(arr):
n = len(arr)
for i in range(n):
swapped = False
for j in range(n - i - 1):
if arr[j] > arr[j + 1]:
arr[j], arr[j + 1] = arr[j + 1], arr[j]
swapped = True
if not swapped: # 優化:無交換代表已有序
break
return arr插入排序 (Insertion Sort)#
將陣列分為「已排序區」與「未排序區」,逐一將未排序元素插入正確位置。
| 特性 | 說明 |
|---|---|
| 時間複雜度 | 最好 O(n)、最壞/平均 O(n²) |
| 空間複雜度 | O(1),原地排序 |
| 穩定性 | 穩定 |
插入排序程式碼
def insertion_sort(arr):
for i in range(1, len(arr)):
key = arr[i]
j = i - 1
while j >= 0 and arr[j] > key:
arr[j + 1] = arr[j]
j -= 1
arr[j + 1] = key
return arr為何插入排序優於冒泡排序?
兩者時間複雜度相同,但冒泡的「交換」需要 3 次賦值,插入的「移動」只需 1 次。實測顯示,插入排序比冒泡排序快約 3-7 倍。
選擇排序 (Selection Sort)#
每次從未排序區選出最小元素,放到已排序區末尾。
| 特性 | 說明 |
|---|---|
| 時間複雜度 | 最好/最壞/平均皆為 O(n²) |
| 空間複雜度 | O(1),原地排序 |
| 穩定性 | 不穩定 |
選擇排序程式碼
def selection_sort(arr):
n = len(arr)
for i in range(n):
min_idx = i
for j in range(i + 1, n):
if arr[j] < arr[min_idx]:
min_idx = j
arr[i], arr[min_idx] = arr[min_idx], arr[i]
return arr選擇排序是不穩定的!例如
[5, 8, 5, 2, 9],第一次選擇最小值 2 與第一個 5 交換後,兩個 5 的相對順序改變了。
實務應用建議#
- 小規模資料:插入排序是首選
- 幾乎有序的資料:插入排序效率接近 O(n)
- 工業級排序函式:當區間元素 <= 4 時,通常切換為插入排序