STL 提供六大排序相關演算法,各有適用場景與效能特性。本文依照《Effective STL》條款 31 脈絡,系統比較 sort、stable_sort、partial_sort、nth_element、partition、stable_partition,並給出決策流程圖與容器相容性表。
| 演算法 | 用途 | 穩定性 | 迭代器需求 | 平均複雜度 | 典型場景 |
|---|---|---|---|---|---|
sort | 全排序 | ❌ 不穩定 | RandomAccess | O(N log N) | 一般排序、需完整有序序列 |
stable_sort | 全排序 | ✅ 穩定 | RandomAccess | O(N log²N) | 相同鍵值保持原序(多欄位排序) |
partial_sort | 前 N 小排序 | ❌ 不穩定 | RandomAccess | O(N log M) | 取 Top-K 且需內部有序 |
nth_element | 第 N 小定位 | ❌ 不穩定 | RandomAccess | O(N) | 中位數、百分位數、Top-K 不需內部有序 |
partition | 單一條件分區 | ❌ 不穩定 | Bidirectional | O(N) | 二分類(如正/負、及格/不及格) |
stable_partition | 單一條件分區 | ✅ 穩定 | Bidirectional | O(N log N) | 分區且保持組內相對順序 |
需要完整有序序列?
├─ 是 → 需穩定? → 是 → stable_sort
│ └─ 否 → sort
└─ 否 → 只需前 K 小且有序? → partial_sort
→ 只需第 K 小/中位數/百分位? → nth_element
→ 只需滿足條件者集中在前? → 需穩定? → stable_partition
└─ 否 → partition
bool qualityCompare(const Widget& a, const Widget& b) { return a.quality() > b.quality(); }
bool isPremium(const Widget& w) { return w.quality() >= PREMIUM_THRESHOLD; }
vector widgets = ...;
// 1. 取品質前 20 並內部排序
partial_sort(widgets.begin(), widgets.begin()+20, widgets.end(), qualityCompare);
// 2. 只取前 20 不需內部排序
nth_element(widgets.begin(), widgets.begin()+20, widgets.end(), qualityCompare);
// 3. 找中位數品質
auto mid = widgets.begin() + widgets.size()/2;
nth_element(widgets.begin(), mid, widgets.end(), qualityCompare);
// 4. 找品質前 25% 門檻
auto p25 = widgets.begin() + widgets.size()/4;
nth_element(widgets.begin(), p25, widgets.end(), qualityCompare);
// 5. 將優質品集中在前(不保證內部順序)
auto goodEnd = partition(widgets.begin(), widgets.end(), isPremium);
// 6. 同上但保持優質品內部原序
auto goodEnd = stable_partition(widgets.begin(), widgets.end(), isPremium);
vector、deque、string、array → 支援所有六大演算法。partition/stable_partition;list::sort() 內建穩定排序;需 partial_sort/nth_element 時,複製到 vector 處理再回寫。set/map...):本身有序,無需額外排序。partition < stable_partition < nth_element < partial_sort < sort < stable_sort
選擇原則:**滿足需求的最輕量演算法**,既表達意圖清晰又高效。
「不要用殺雞刀切豆腐:只需分區時別呼叫 sort,只需中位數時別呼叫 partial_sort。正確的演算法選擇是零成本的最佳化。」