步步看懂

Quick Sort

快速排序

用互動動畫一步步看懂快速排序(Quick Sort):自選基準(首、尾、三數取中),看分割過程、遞迴呼叫堆疊,並示範最差情況。

基準值(pivot)的選法

「已排序」對首/尾基準是最差情況(每次只切掉一個數字);「平衡分割」是為尾基準排好的最佳情況。換成三數取中,再按一次「已排序」看看差別。

100801302903404505706
比較次數
0
交換次數
0
最大遞迴深度
0

快速排序在做什麼

快速排序也是分而治之,但「難的工作」放在拆分這一步:

  1. 挑基準:從區間挑一個數字當基準,先換到區間最右邊。
  2. 分割:用 j 由左往右掃描。比基準小的數字,就和 i 位置的數字交換,放進左邊的「小於基準區」,i 往前一格;不比基準小的就留在右邊。
  3. 放定基準:掃描完畢,把基準換到 i 的位置。它左邊都比它小,右邊都不比它小,所以這個數字已經在最終位置。
  4. 遞迴:分別對基準左邊、右邊的區間重複同樣的事。只剩一個數字的區間不用再處理。

基準怎麼選,差很多

  • 首、尾:最簡單,但遇到已排序的資料會是最差情況。
  • 三數取中:取首、中、尾三個數字的中位數,已排序的資料也能切得很平均。

在上方切換三種選法,再按「已排序」比較:用首或尾時,比較次數是 n(n − 1) / 2,遞迴深度是 n;改用三數取中,兩個數字都小很多。

為什麼最差是 O(n²)、平均是 O(n log n)

最差情況時,每次只切掉一個數字:第一輪比較 n − 1 次,第二輪 n − 2 次……加起來 n(n − 1) / 2,呼叫堆疊也疊到 n 層。

如果每次都切在中間,只需要 log n 層,每一層總共比較約 n 次,就是 n log n。按「平衡分割」可以看到這種最佳情況,8 個數字只要 4 層(最差情況要 8 層)。隨機的資料平均下來很接近這種情況,這就是平均 O(n log n) 的由來。

複雜度

最佳O(n log n)
平均O(n log n)
最差O(n²)
額外空間O(log n)
穩定否

常見問題

快速排序的最差情況是什麼時候?
每次選到的基準剛好是最小或最大的數字,分割後一邊是空的、另一邊只少了一個數字。例如對已排序的資料用「首」或「尾」當基準,就會變成 O(n²),遞迴也會深到 n 層。
怎麼避免最差情況?
常見做法是「三數取中」(取首、中、尾的中位數)或隨機選基準。本頁可以切換基準的選法,再按「已排序」看比較次數和遞迴深度的差別。
快速排序比合併排序快嗎?
實務上常常是,因為它在原陣列上就地分割,額外空間只有遞迴堆疊 O(log n),對快取也友善。代價是最差情況 O(n²),而且不穩定。
快速排序是穩定的嗎?
不是。把基準或較小的數字換到前面時,可能讓原本相等的兩個值改變相對順序。
為什麼要先把基準換到最右邊?
這樣掃描時基準不會被移動,等掃描完,再一次換到它的最終位置就好。