面對 N ≤ 10⁵ 規模整數排序,基礎 O(N²) 算法(冒泡、插入)在逆序、大量隨機數據下會超時。本文記錄從冒泡、插入到希爾排序的優化過程,並分析各測試數據特點對算法選擇的啟示。
N 及 N 個長整型整數。| 數據集 | 規模 | 特點 |
|---|---|---|
| 0 | 1 | 單元素邊界 |
| 1 | 11 | 基本正確性 |
| 2 | 10³ | 隨機整數 |
| 3 | 10⁴ | 隨機整數 |
| 4/5/6/7/8 | 10⁵ | 隨機/順序/逆序/近有序/小範圍正整數 |
void Bubble_Sort(int *a, int n) {
bool flag;
for (int i = n-1; i > 0; i--) {
flag = true;
for (int j = 0; j < i; j++)
if (a[j] > a[j+1]) { swap(a[j], a[j+1]); flag = false; }
if (flag) break; // 本輪無交換,已有序
}
}
測試點 4、6、8 超時(O(N²) 在 10⁵ 逆序/隨機過慢)。
void Insert_Sort(int *a, int n) {
for (int i = 1; i < n; i++) {
int tmp = a[i], j;
for (j = i; j > 0 && a[j-1] > tmp; j--) a[j] = a[j-1];
a[j] = tmp;
}
}
測試點 6(逆序 10⁵)超時,近有序數據較快但最壞情況仍 O(N²)。
void Shell_Sort(int *a, int n) {
for (int gap = n/2; gap > 0; gap /= 2)
for (int i = gap; i < n; i++) {
int tmp = a[i], j;
for (j = i; j >= gap && a[j-gap] > tmp; j -= gap)
a[j] = a[j-gap];
a[j] = tmp;
}
}
全測試點通過。希爾排序平均 O(N¹·⁵),對 10⁵ 規模極具優勢。
#includevoid Shell_Sort(int *a, int n) { for (int gap = n/2; gap > 0; gap /= 2) for (int i = gap; i < n; i++) { int tmp = a[i], j; for (j = i; j >= gap && a[j-gap] > tmp; j -= gap) a[j] = a[j-gap]; a[j] = tmp; } for (int i = 0; i < n; i++) { printf("%d", a[i]); if (i != n-1) printf(" "); else printf("\n"); } } int main() { int N; scanf("%d", &N); int a[N]; for (int i = 0; i < N; i++) scanf("%d", &a[i]); Shell_Sort(a, N); return 0; }
同一問題,算法選擇決定成敗。理解數據分布特徵,選擇合適時間複雜度算法,是競賽與工程優化的核心能力。希爾排序以極簡代碼實現了亞線性級效能,是中等規模排序的「性價比之王」。