iT邦幫忙

2026 iThome 鐵人賽

DAY 6
0

昨天理解 Bubble Sort 怎麼運作之後,今天要試著把紙上理解的流程真正轉換成程式碼。

先簡單回顧 Bubble Sort 的三個重要概念:

  • Compare(比較):比較兩個相鄰的數字。
  • Swap(交換):如果左邊比右邊大,就交換兩個數字的位置。
  • Pass(回合):從頭進行一次相鄰元素比較的完整回合。

假設今天有一組資料:

const arr = [5, 3, 8, 1];

昨天試著一步一步把它排好,但真的要轉換成程式碼時,我得先思考:要怎麼把 Compare、Swap、Pass 寫成程式?


開始寫之前,我先想了三個問題

回想昨天手算 Bubble Sort 的流程,我覺得程式至少需要處理三件事情:

  1. 如何比較並交換兩個相鄰的數字?
  2. 如何讓最大的數字經過比較後留在最後面?
  3. 完成第一輪之後,迴圈要怎麼繼續進行第二輪、第三輪?

帶著這三個問題,我開始嘗試把 Bubble Sort 寫成 TypeScript。

但真正開始實作之後,才發現還有一些原本沒有注意到的細節。


第一個問題:交換時,原本的值被覆蓋了

一開始處理 Swap 時,我直覺寫成:

arr[i] = arr[i + 1];
arr[i + 1] = arr[i];

但第一行執行後,原本 arr[i] 的值就已經被覆蓋,因此需要先用一個變數暫存:

temp = arr[i];          // 暫存左邊的數字
arr[i] = arr[i + 1];   // 將右邊的數字移到左邊
arr[i + 1] = temp;      // 將暫存的數字移到右邊

這樣才能在不遺失原本數值的情況下完成交換。


實作之後,又遇到了新的問題

解決 Swap 之後,我又陸續遇到幾個問題:

  1. 該如何讓程式自動進行下一個 Pass?
  2. 內層迴圈需要比較到最後一個 index 嗎?
  3. 為什麼每完成一輪,比較範圍就可以縮小?
  4. 只剩一個元素時,外層迴圈還需要再執行嗎?

實作時,我先使用一個 for,確認第一輪的 Compare 與 Swap 是否符合預期,再來思考該如何進行下一輪。

第一輪跑完後:

[5, 3, 8, 1]
↓
[3, 5, 1, 8]

最大的 8 的確被推到最後面,代表第一輪的比較與交換方向是正確的。

但前面的 [3, 5, 1] 還沒有排序完成,接下來就需要讓相同的比較流程繼續進行第二輪、第三輪,因此使用雙重迴圈:

  • 外層迴圈:控制 Pass,以及目前還需要比較的範圍。
  • 內層迴圈:負責這一輪相鄰元素的 Compare 與 Swap。

每完成一輪,最大的數字就會被推到目前比較範圍的最後面,因此下一輪可以縮小比較範圍,不需要再次比較已經排好的部分。


最後完成的 Bubble Sort

整理前面的問題後,最後寫出的版本:

const arr = [5, 3, 8, 1];

let temp = 0;

for (let j = arr.length; j > 1; j--) {
  console.log("目前 Pass 的比較範圍", j);

  for (let i = 0; i < j - 1; i++) {
    if (arr[i] > arr[i + 1]) {
      temp = arr[i];          // 暫存左邊的數字
      arr[i] = arr[i + 1];   // 將右邊的數字移到左邊
      arr[i + 1] = temp;      // 將暫存的數字移到右邊

      console.log("[如果左邊的數字比較大,就交換]", arr);
    } else {
      console.log("[不需要交換]", arr);
    }
  }
}

透過 console 可以看到每一輪實際發生的事情:

目前 Pass 的比較範圍 4 // 第一輪
[如果左邊的數字比較大,就交換] [3, 5, 8, 1] // 5、3 交換
[不需要交換] [3, 5, 8, 1] // 5、8 不需要交換
[如果左邊的數字比較大,就交換] [3, 5, 1, 8] // 8、1 交換

目前 Pass 的比較範圍 3 // 第二輪
[不需要交換] [3, 5, 1, 8] // 3、5 不需要交換
[如果左邊的數字比較大,就交換] [3, 1, 5, 8] // 5、1 交換

目前 Pass 的比較範圍 2 // 第三輪
[如果左邊的數字比較大,就交換] [1, 3, 5, 8] // 3、1 交換

最後成功得到:

[1, 3, 5, 8]

從理解到真正寫成程式

這次實作其中一個收穫,是開始思考:當只剩下一個元素時,還有需要再跑一輪嗎?

實際測試後發現,就算多跑一輪也不會影響最後的排序結果,但這一輪其實沒有進行任何比較,所以是沒有必要的。

另外,透過實際寫程式碼,也讓我更了解兩層迴圈各自在做什麼。內層迴圈負責一次 Pass 裡的比較與交換;外層迴圈則負責讓 Pass 繼續進行,而且每完成一輪,就可以縮小下一輪需要比較的範圍。

原本覺得很直覺的「比較、交換、再跑下一輪」,真正轉換成程式碼之後,才發現每一個步驟都需要轉換成明確的程式條件。

這邊也請 AI 做了一個小工具,可以實際操作 Bubble Sort 每一步「比較」與「交換」的過程,幫助自己更熟悉整個排序流程。

https://chatgpt.com/s/w_6aa27bac36448191811e265c828916ab


延伸閱讀

文章完成後,我也找了一些其他 Bubble Sort 的實作方式,看看不同的寫法:

iT 邦幫忙,〈Bubble Sort 相關實作〉
https://ithelp.ithome.com.tw/articles/10223288

PJCHENder,〈[演算法] 氣泡排序法(Bubble Sort)〉
https://pjchender.blogspot.com/2017/09/bubble-sort.html


上一篇
【D5】排序還有分很多種?Bubble Sort 又是什麼?
下一篇
【D7】Vue 實作 — 學了一週演算法,今天終於開始建立環境
系列文
看得到的演算法:用 Vue 3 打造演算法互動視覺化平台7
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言