雖然生產環境直接用 Arrays.sort()/Collections.sort()(TimSort,O(n log n) 穩定),但理解經典算法是面試必考、演算法思維訓練、特定場景(如外部排序、Top-K、近似有序資料)優化的基石。本文整理 14 種常見排序,附完整 Java 實現、原理圖解、效能實測(20,000 筆隨機整數)與選型建議。
public static void bubbleSort(int[] a) {
for (int i = 0; i < a.length; i++)
for (int j = 0; j < a.length - i - 1; j++)
if (a[j] > a[j+1]) swap(a, j, j+1);
}
public static void bubbleSortAdv(int[] a) {
boolean swapped = true;
for (int limit = a.length - 1; swapped && limit > 0; limit--) {
swapped = false;
for (int i = 0; i < limit; i++)
if (a[i] > a[i+1]) { swap(a, i, i+1); swapped = true; }
}
}
public static void bubbleSortAdv2(int[] a) {
int limit = a.length - 1;
while (limit > 0) {
int lastSwap = 0;
for (int i = 0; i < limit; i++)
if (a[i] > a[i+1]) { swap(a, i, i+1); lastSwap = i+1; }
limit = lastSwap;
}
}
public static void selectSort(int[] a) {
for (int i = 0; i < a.length; i++) {
int min = i;
for (int j = i+1; j < a.length; j++)
if (a[j] < a[min]) min = j;
swap(a, i, min);
}
}
public static void insertSort(int[] a) {
for (int i = 1; i < a.length; i++) {
int tmp = a[i], j = i-1;
while (j >= 0 && a[j] > tmp) a[j+1] = a[j--];
a[j+1] = tmp;
}
}
public static void insertSortBin(int[] a) {
for (int i = 1; i < a.length; i++) {
int tmp = a[i], pos = Arrays.binarySearch(a, 0, i, tmp);
if (pos < 0) pos = -pos - 1;
System.arraycopy(a, pos, a, pos+1, i-pos);
a[pos] = tmp;
}
}
public static void shellSort(int[] a) {
for (int gap = a.length/2; gap > 0; gap /= 2)
for (int i = gap; i < a.length; i++) {
int tmp = a[i], j = i;
while (j >= gap && a[j-gap] > tmp) { a[j] = a[j-gap]; j -= gap; }
a[j] = tmp;
}
}
public static int[] mergeSort(int[] a) {
if (a.length <= 1) return a;
int mid = a.length/2;
int[] left = mergeSort(Arrays.copyOfRange(a, 0, mid));
int[] right = mergeSort(Arrays.copyOfRange(a, mid, a.length));
return merge(left, right);
}
private static int[] merge(int[] a, int[] b) {
int[] r = new int[a.length + b.length];
int i=0,j=0,k=0;
while (i
public static void quickSort(int[] a, int lo, int hi) {
if (lo >= hi) return;
int i = lo, j = hi, pivot = a[lo];
while (i < j) {
while (i < j && a[j] >= pivot) j--;
if (i < j) a[i++] = a[j];
while (i < j && a[i] <= pivot) i++;
if (i < j) a[j--] = a[i];
}
a[i] = pivot;
quickSort(a, lo, i-1);
quickSort(a, i+1, hi);
}
public static void quickSort(int[] a) { quickSort(a, 0, a.length-1); }
public static void heapSort(int[] a) {
for (int i = (a.length-2)/2; i >= 0; i--) maxHeapify(a, i, a.length);
for (int i = a.length-1; i > 0; i--) {
swap(a, 0, i);
maxHeapify(a, 0, i);
}
}
private static void maxHeapify(int[] a, int i, int len) {
int tmp = a[i];
for (int j = 2*i+1; j < len; j = 2*j+1) {
if (j+1 < len && a[j+1] > a[j]) j++;
if (a[j] < tmp) break;
a[i] = a[j]; i = j;
}
a[i] = tmp;
}
建構 BST 再中序遍歷。平均 O(n log n),最差 O(n²)(退化鏈表),需自平衡樹(AVL/紅黑)保證效能,教學用途為主。
| 算法 | 耗時 (ms) | 複雜度 | 穩定性 | 備註 |
|---|---|---|---|---|
| bubbleSort | 766 | O(n²) | ✅ | 教學用 |
| bubbleSortAdv | 662 | O(n²) | ✅ | 旗標優化 |
| bubbleSortAdv2 | 647 | O(n²) | ✅ | 記錄最後交換 |
| selectSort | 252 | O(n²) | ❌ | 交換少 |
| insertSort | 218 | O(n²) | ✅ | 近似有序極快 |
| insertSortBin | 127 | O(n²) | ✅ | 二分查找位置 |
| shellSort | 2 | ~O(n^1.3) | ❌ | 增量序列關鍵 |
| mergeSort | 3 | O(n log n) | ✅ | 穩定、需額外空間 |
| quickSort | 1 | O(n log n) | ❌ | 實際最快 |
| heapSort | 2 | O(n log n) | ❌ | 保證上界 |
Arrays.sort 物件版)Arrays.sort 基本型版(雙軸快排)Arrays.sort/Collections.sort,經過極致優化(TimSort/雙軸快排)、穩定、無 Bug。排序算法是演算法皇冠上的明珠。從冒泡的樸素到快排的優雅,從歸併的穩健到堆排的剛性,每種算法都折射出「分治」、「隨機化」、「資料結構輔助」等核心思想。掌握它們的適用邊界,比背誦程式碼更有價值。下次面試被問到「為什麼快排通常比歸併快?」時,你可以自信地回答:原地分區、快取友好、分支預測友好、避免額外記憶體分配與拷貝。