📊 6 種演算法 · 各自獨立設定 · 逐步視覺化
排序演算法視覺化
每個演算法都有獨立的柱子數量、播放速度與操作按鈕,互不影響。
反覆比較相鄰元素,若順序錯誤則交換,最大值像泡泡浮向末端。
每輪從未排序區掃描找出最小值,交換至已排序區末端。
逐一取出元素,插入左側已排序序列的正確位置,如同整理手牌。
選取 Pivot,小於放左、大於放右,遞迴分治左右子序列。
分治法:遞迴對半拆分至單一元素,再將有序子序列兩兩合併。
先建立最大堆積,重複取出堆頂(最大值)並重整堆,直到排序完成。
📊 複雜度對照表
| 演算法 | 平均時間 | 最壞時間 | 空間 | 穩定 |
|---|---|---|---|---|
| 冒泡排序 | O(n²) | O(n²) | O(1) | ✅ |
| 選擇排序 | O(n²) | O(n²) | O(1) | ❌ |
| 插入排序 | O(n²) | O(n²) | O(1) | ✅ |
| 快速排序 | O(n log n) | O(n²) | O(log n) | ❌ |
| 合併排序 | O(n log n) | O(n log n) | O(n) | ✅ |
| 堆積排序 | O(n log n) | O(n log n) | O(1) | ❌ |
❓ 常見問題
O(n²) 和 O(n log n) 的效率差距有多大?
以 n=1,000 為例:O(n²) 約 1,000,000 次操作;O(n log n) 只需約 10,000 次,差了 100 倍。n=1,000,000 時差距更達萬倍。
快速排序最壞是 O(n²),為什麼還常用?
當每次隨機選 Pivot 時,觸發最壞情況的機率極低,平均表現是 O(n log n),且 cache 效能好,實際執行速度通常優於合併排序。
插入排序何時勝過快速排序?
當資料幾乎有序時,插入排序接近 O(n)。Python 的 Timsort 就在小區段或近似有序時切換到插入排序。
「穩定排序」是什麼意思?
相同值的元素排序後仍保持原本相對順序。冒泡、插入、合併是穩定的;選擇、快速、堆積不穩定。
JavaScript 的 Array.sort() 用的是哪種排序?
V8 引擎(Node.js / Chrome)使用 TimSort,一種結合合併排序與插入排序的混合演算法。它是穩定的,平均時間複雜度 O(n log n),對近乎有序的資料尤其快。
什麼是「原地排序(In-place)」?
排序過程中不需要額外開闢與輸入等比例的記憶體空間,僅使用 O(1) 或 O(log n) 的輔助空間。冒泡、選擇、插入、快速、堆積排序都是原地排序;合併排序則需要 O(n) 額外空間。
合併排序為什麼一定需要 O(n) 額外空間?
合併兩個有序子陣列時,必須同時讀取兩側元素再按順序填回,若直接在原陣列操作會覆蓋還未讀到的值。因此需要暫存左半或整段的副本,最多使用 O(n) 的額外記憶體。
堆積排序和快速排序都是 O(n log n),哪個實際更快?
實務上快速排序通常更快。堆積排序的記憶體存取順序較跳躍(父子節點距離遠),cache 命中率低;快速排序的分區操作是連續存取,cache 效率高。但在最壞情況保證上,堆積排序更可靠。
快速排序 Pivot 的選擇策略有哪些?
常見策略:① 固定選第一或最後一個元素(最簡單,但有序時退化到 O(n²));② 隨機選取(大幅降低最壞情況機率);③ 三數取中(取首、尾、中位數的中間值);④ Median of Medians(可保證最壞 O(n log n),但常數大,較少用)。
各程式語言標準函式庫用的是什麼排序?
Python:TimSort(合併 + 插入)。Java:基本型別用雙 Pivot 快速排序,物件用 TimSort。C++ STL:introsort(快速 + 堆積 + 插入的混合,保證 O(n log n))。Swift / Rust:也採用 TimSort 或類似的混合策略。