排序演算法視覺化工具

以長條圖逐步播放 7 種代表性的排序演算法,顯示每一步比較陣列中的哪些元素、改寫了哪個位置。可以改變資料個數與初始排列(隨機、幾乎已排序、反序、重複值多),確認比較次數與寫入次數如何變化。對於練習逐行追蹤排序程式也很有幫助,例如日本基本資訊技術士考試(科目 B)等資訊類證照考試中的程式追蹤題。

設定

排序過程

 

比較次數
–
寫入次數
–
步驟
–

比較中 寫入 位置已確定

相同資料下的比較

以下是用 7 種演算法排序與上方相同資料時的次數。改變資料個數或初始排列,哪一種較有利也會隨之改變。

演算法比較次數寫入次數時間複雜度(平均/最差)穩定

一次交換計為 2 次寫入。快速排序以最後一個元素為基準值(樞紐,pivot)(Lomuto 分割法),希爾排序使用 1、4、13、40……的間隔序列,次數會因實作而不同。資料個數在 20 以下時,會在長條下方顯示數值。

比較排序的基礎:3 種 O(n²) 演算法

泡沫排序反覆比較相鄰的兩個元素,把較大者往後移,每走完一輪,最大值就會在末端確定。選擇排序從剩餘元素中找出最小值並與前端交換,因此比較次數固定為 n(n−1)/2 次,但交換最多只有 n−1 次。插入排序是把下一個值插入已排序部分的正確位置,對於幾乎已排序的資料,比較次數只需約 n 次。這 3 種的平均時間複雜度都是 O(n²),資料一多就會急遽變慢。將資料個數設為 64,切換「隨機」與「幾乎已排序」,可以看到插入排序,以及在一輪中沒有交換即結束的泡沫排序,比較次數大幅減少,而選擇排序維持 2016 次不變。

分治法的 O(n log n):合併排序與快速排序

合併排序將陣列分成兩半各自排序,再從前端比較兩段已排序的序列,合併(merge)成一段。分割的層數為 log₂ n 層,每層的工作量與 n 成正比,因此對任何資料都是 O(n log n),但需要 n 個元素份的額外記憶體。快速排序把小於基準值(樞紐)的元素放到前面、大於的放到後面,再對各部分繼續分割。平均為 O(n log n),實務上也很快;但若資料已排序又以端點元素為樞紐,分割會嚴重失衡,退化為 O(n²)。將初始排列設為「反序」並選擇快速排序,可以看到比較次數接近 n(n−1)/2。實際的函式庫會採取對策,例如以 3 個值的中位數為樞紐,或在分割失衡時改用堆積排序(內省排序,introsort)。

堆積排序與希爾排序

堆積排序在陣列中建立滿足「父節點大於子節點」條件的二元樹(二元堆積),然後反覆將根部的最大值與末端交換,並把堆積縮小 1。陣列第 i 個元素的子節點是第 2i+1 與第 2i+2 個元素。即使在最差情況下也是 O(n log n),且不需要額外的記憶體,但因為會比較相距很遠的元素,快取效率不佳。希爾排序對間隔一定距離的元素進行插入排序,並逐步縮小間隔。先把遠處的元素大幅移動,就能減少最後一般插入排序的工作量。

穩定排序與時間複雜度的解讀

排序後,值(鍵)相同的元素仍保持原本先後順序的排序,稱為穩定排序。例如把員工依部門排序時,同一部門內仍維持員工編號的順序,就是這種性質。泡沫排序、插入排序、合併排序是穩定的,而選擇排序、快速排序、堆積排序、希爾排序一般不穩定。O(n²) 或 O(n log n) 等時間複雜度,表示資料個數 n 變大時次數的增加方式。當 n = 1000 時,n² 為 100 萬,n log₂ n 約為 1 萬,因此資料量大時 O(n log n) 的演算法壓倒性地有利。已知僅靠比較來排序的方法,在最差情況下不可能比 O(n log n) 更快。

練習相關題目

以泡沫排序將陣列 5, 3, 8, 1, 4 依升冪排列。從開頭比較相鄰的兩個元素,若左側較大就交換,這樣的操作進行到末尾1次(1輪)後,陣列為下列何者?

  1. A1, 3, 8, 5, 4
  2. B3, 5, 1, 4, 8
  3. C1, 3, 4, 5, 8
查看答案與解析

正確答案:B. 3, 5, 1, 4, 8

交換5與3得到 3, 5, 8, 1, 4;5與8不變;交換8與1得到 3, 5, 1, 8, 4;交換8與4得到 3, 5, 1, 4, 8。1輪就把最大值8送到末尾並確定其位置,下一輪再以相同方式排列其餘4個元素。1, 3, 8, 5, 4 是找出最小值並與開頭交換的選擇排序進行1輪後的陣列,1, 3, 4, 5, 8 則是全部排序完成的結果。

以選擇排序(從未排序部分找出最小值,並與未排序部分的開頭交換)將陣列 29, 10, 14, 37, 13 依升冪排列。進行此操作2次後,陣列為下列何者?

  1. A10, 13, 14, 37, 29
  2. B10, 14, 29, 37, 13
  3. C10, 14, 13, 29, 37
查看答案與解析

正確答案:A. 10, 13, 14, 37, 29

第1次把整體最小值10與開頭的29交換,得到 10, 29, 14, 37, 13。第2次把第2個以後的最小值13與第2個的29交換,得到 10, 13, 14, 37, 29。選擇排序的比較次數固定為 n(n−1)/2 次,但每次操作最多只交換1次,因此對寫入成本高的資料有時較有利。10, 14, 29, 37, 13 是插入排序插入2個元素後的陣列,10, 14, 13, 29, 37 則是泡沫排序進行2輪後的陣列。

以插入排序將有10個元素的陣列依升冪排列。依序取出第2個以後的元素,從左側相鄰的元素開始依序比較,直到找到小於或等於取出值的元素,或到達開頭為止。一開始就是升冪時與一開始是降冪時,比較次數的組合為下列何者?

  1. A都是45次
  2. B10次與100次
  3. C9次與45次
查看答案與解析

正確答案:C. 9次與45次

若已是升冪,取出的值只要與左側相鄰元素比較1次就能決定位置,9個元素合計9次。若是降冪,第 i 個取出的值要與左側全部 i 個元素比較,合計 1 + 2 + … + 9 = 45次。由此可見插入排序最佳為 O(n)、最差為 O(n²),會隨輸入大幅改變,對幾乎已排序的資料非常快。利用這個性質,先對間隔一定距離的元素進行插入排序的就是希爾排序,Timsort 等也會在短區間使用插入排序。

即使在最差情況下時間複雜度也是 O(n log n),且幾乎不使用工作用陣列等額外記憶體就能排序的演算法為下列何者?

  1. A合併排序
  2. B堆積排序
  3. C快速排序
查看答案與解析

正確答案:B. 堆積排序

堆積排序在陣列中建立二元堆積,並反覆把根部的最大值與末尾交換、縮小堆積,因此最差也是 O(n log n),額外空間只需常數。合併排序最差也是 O(n log n),但在陣列上進行時需要與 n 成正比的工作空間。快速排序平均為 O(n log n),實務上很快,但視樞紐的選法與資料而定,可能變成 O(n²)。此外,堆積排序會比較相距很遠的元素,因此快取效率差,也不是穩定排序。

(姓名, 分數)的資料 (A, 80)、(B, 70)、(C, 80)、(D, 70) 依此順序排列。以穩定排序依分數升冪重新排列時,姓名的順序為下列何者?

  1. AB, D, A, C
  2. BD, B, A, C
  3. CB, D, C, A
查看答案與解析

正確答案:A. B, D, A, C

在穩定排序中,鍵(這裡是分數)相同的元素之間,會維持排序前的順序。70分的 B 與 D 依原順序為 B、D,80分的 A 與 C 依原順序為 A、C,因此結果為 B, D, A, C。穩定的排序有泡沫排序、插入排序、合併排序,而選擇排序、快速排序、堆積排序一般不穩定。使用穩定排序,就能做到先依姓名排序、再依分數重新排序這類以多個鍵進行的排序。

快速排序的時間複雜度變成 O(n²) 的典型情況為下列何者?

  1. A資料隨機排列,且隨機選擇樞紐(基準值)的情況
  2. B資料個數為2的冪次的情況
  3. C資料已排序,且總是以開頭元素為樞紐的情況
查看答案與解析

正確答案:C. 資料已排序,且總是以開頭元素為樞紐的情況

快速排序把元素分成小於樞紐與大於樞紐的部分,再對各部分繼續分割。若資料已排序又總是以開頭為樞紐,每次樞紐都是最小值,分割會偏成「0個與其餘全部」,因此比較次數為 n(n−1)/2 次(n = 100 時為4,950次)。若隨機選擇樞紐,或取3個值的中位數,持續發生偏斜分割的可能性就非常小。資料個數與時間複雜度無關。

在合併排序中,把已依升冪排序的兩個序列 1, 4, 7, 9 與 2, 3, 8, 10,以「比較兩者開頭並輸出較小者」的方式反覆進行,合併成一個序列。其中一個序列變空時,其餘部分不比較直接輸出。比較次數為幾次?

  1. A4次
  2. B7次
  3. C8次
查看答案與解析

正確答案:B. 7次

依序比較1與2、4與2、4與3、4與8、7與8、9與8、9與10,此時第一個序列已空,剩下的10不比較直接輸出。比較共7次,相當於合併長度 m 與 n 的序列時的最多次數 m + n − 1 = 7。合併只需把已排序的序列從開頭各看一次,為 O(m + n),合併排序重複 log₂ n 層,因此整體為 O(n log n)。

常見問題

哪一種排序最快?

取決於資料。一般資料多半是快速排序較快;若希望最差情況也保證 O(n log n),可用合併排序或堆積排序;資料幾乎已排序或數量很少時,適合插入排序。實際程式語言的標準函式庫,使用的是結合這些方法的混合排序(內省排序或 Timsort)。

比較次數與寫入次數代表什麼?

比較次數是檢查兩個元素大小的次數。寫入次數是改寫陣列元素的次數,一次交換計為 2 次。比較成本高的資料(如長字串)以比較次數、寫入成本高的儲存裝置(如快閃記憶體)以寫入次數,對實際速度影響較大。

考試中會怎麼出題?

在日本的基本資訊技術士考試、應用資訊技術士考試等資訊類證照考試中,常見的題型有:填寫排序程式的空格、回答某個時間點的陣列狀態、選出時間複雜度或穩定性。使用本工具的「前進一步」,把陣列的變化與自己的預測相對照,可以練習追蹤。

增加資料個數時,次數會增加多少?

O(n²) 的演算法在資料加倍時,次數約變為 4 倍。O(n log n) 的演算法則約為 2 倍多一點。將資料個數依序設為 16、32、64,查看相同資料下的比較表即可確認。

相關術語

時間複雜度(大O符號) 穩定排序 二元堆積

相關計算工具

半導體、電子電路與資訊計算工具 →