演算法複雜度理論比較
| 演算法 | 平均時間 | 最壞時間 | 空間 | 穩定性 | 備註 |
| 氣泡排序 | O(n²) | O(n²) | O(1) | 穩定 | 教學用,實務極少用 |
| 插入排序 | O(n²) | O(n²) | O(1) | 穩定 | 小資料/近乎有序時極快 |
| 選擇排序 | O(n²) | O(n²) | O(1) | 不穩定 | 交換次數最少 O(n) |
| 快速排序 | O(n log n) | O(n²) | O(log n) | 不穩定 | 實務首選,.NET 內建即採用 |
C# 完整實作程式碼
using System;
public interface ISortAlgorithm
{
void Sort(int[] array);
string Name { get; }
}
// 1. 氣泡排序
public class BubbleSort : ISortAlgorithm
{
public string Name => "Bubble Sort";
public void Sort(int[] arr)
{
int n = arr.Length;
for (int i = 0; i < n - 1; i++)
{
bool swapped = false;
for (int j = 0; j < n - 1 - i; j++)
{
if (arr[j] > arr[j + 1])
{
(arr[j], arr[j + 1]) = (arr[j + 1], arr[j]); // C# 7 元組交換
swapped = true;
}
}
if (!swapped) break; // 優化:提前結束
}
}
}
// 2. 插入排序
public class InsertionSort : ISortAlgorithm
{
public string Name => "Insertion Sort";
public void Sort(int[] arr)
{
for (int i = 1; i < arr.Length; 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;
}
}
}
// 3. 選擇排序
public class SelectionSort : ISortAlgorithm
{
public string Name => "Selection Sort";
public void Sort(int[] arr)
{
for (int i = 0; i < arr.Length - 1; i++)
{
int minIdx = i;
for (int j = i + 1; j < arr.Length; j++)
if (arr[j] < arr[minIdx]) minIdx = j;
if (minIdx != i)
(arr[i], arr[minIdx]) = (arr[minIdx], arr[i]);
}
}
}
// 4. 快速排序 (原地分區)
public class QuickSort : ISortAlgorithm
{
public string Name => "Quick Sort";
public void Sort(int[] arr) => QuickSortInternal(arr, 0, arr.Length - 1);
private void QuickSortInternal(int[] arr, int low, int high)
{
if (low >= high) return;
int pivot = arr[low]; // 簡單選擇首元素為基準
int i = low, j = high;
while (i < j)
{
while (i < j && arr[j] >= pivot) j--;
if (i < j) arr[i++] = arr[j];
while (i < j && arr[i] <= pivot) i++;
if (i < j) arr[j--] = arr[i];
}
arr[i] = pivot;
QuickSortInternal(arr, low, i - 1);
QuickSortInternal(arr, i + 1, high);
}
}
效能測試框架
public static class SortBenchmark
{
public static void Run(int arraySize = 100_000, int testRounds = 5)
{
var algorithms = new ISortAlgorithm[]
{
new BubbleSort(),
new InsertionSort(),
new SelectionSort(),
new QuickSort(),
new SystemSort() // 對照組:Array.Sort
};
Console.WriteLine($"陣列大小:{arraySize:N0},測試輪數:{testRounds}");
Console.WriteLine(new string('=', 60));
foreach (var algo in algorithms)
{
long totalMs = 0;
for (int round = 0; round < testRounds; round++)
{
int[] data = GenerateRandomArray(arraySize);
int[] copy = (int[])data.Clone();
var sw = System.Diagnostics.Stopwatch.StartNew();
algo.Sort(copy);
sw.Stop();
totalMs += sw.ElapsedMilliseconds;
// 驗證正確性 (僅第一輪)
if (round == 0 && !IsSorted(copy))
Console.WriteLine($" ⚠️ {algo.Name} 排序結果錯誤!");
}
Console.WriteLine($"{algo.Name,-15} 平均耗時:{totalMs / (double)testRounds,8:F1} ms");
}
}
private static int[] GenerateRandomArray(int size)
{
var rnd = new Random(42); // 固定種子確保公平
var arr = new int[size];
for (int i = 0; i < size; i++) arr[i] = rnd.Next(int.MinValue, int.MaxValue);
return arr;
}
private static bool IsSorted(int[] arr)
{
for (int i = 1; i < arr.Length; i++)
if (arr[i - 1] > arr[i]) return false;
return true;
}
}
// 對照組:.NET 內建排序 (Introsort:快速+堆積+插入混合)
public class SystemSort : ISortAlgorithm
{
public string Name => "Array.Sort";
public void Sort(int[] arr) => Array.Sort(arr);
}
實測結果範例 (100,000 筆隨機整數,5 輪平均)
============================================================
Bubble Sort 平均耗時: 12,450.2 ms (約 12.5 秒)
Insertion Sort 平均耗時: 3,210.5 ms (約 3.2 秒)
Selection Sort 平均耗時: 1,850.3 ms (約 1.9 秒)
Quick Sort 平均耗時: 12.3 ms (0.012 秒)
Array.Sort 平均耗時: 8.7 ms (最快)
============================================================
深度分析與避坑指南
- 氣泡排序最慢:雙層迴圈 + 大量交換,教學價值大於實務。
- 插入排序次之:資料近乎有序時接近 O(n),適合小陣列 (通常 < 50)。
- 選擇排序優於氣泡:交換次數固定 O(n),但比較次數仍 O(n²)。
- 快速排序碾壓:分治法 O(n log n),但最壞情況 (已排序陣列 + 首元素基準) 退化 O(n²)。
→ 實務建議:隨機選基準或三數取中法。
- Array.Sort 最強:.NET 使用 Introsort (Quick + Heap + Insertion 混合),自動切換策略,無最壞情況退化。
現代 C# 實務建議
// 99% 情況直接用內建
Array.Sort(array); // 陣列原地排序
list.Sort(); // List 原地排序
var sorted = array.OrderBy(x => x); // LINQ 產生新序列 (穩定排序)
// 自訂比較
Array.Sort(array, (a, b) => b.CompareTo(a)); // 降序
Array.Sort(array, Comparer.Create((a,b) => a - b));
只有在教學、面試、極度受限環境 (無標準庫) 或需要特定穩定性/空間限制時,才手寫排序演算法。