歡迎來到算法的世界!

歡迎!在本章關於算法建模(Modelling with Algorithms)的學習中,我們將探索數學世界中的「食譜」。無論是你使用 GPS 找尋回家的最快路線,還是電腦在整理數以百萬計的檔案,背後都有一個算法(Algorithm)在運作。

別擔心,即使你從未寫過程式,或者覺得「大 O 符號(Big O notation)」聽起來像天書,也不用緊張。我們會將這些概念拆解成任何人都能跟上的簡單邏輯步驟。讓我們開始吧!

1. 什麼是算法?

簡單來說,算法就是解決特定問題的一系列有限指令。把它想像成烤蛋糕的食譜:你準備好材料(輸入/Input),按照順序執行步驟(處理/Process),最後得到一個蛋糕(輸出/Output)。

關鍵組成部分:

  • 初始狀態(Initial State):你開始的地方。
  • 輸入(Input):你提供給算法的數據(例如:一串數字)。
  • 輸出(Output):算法最終產出的結果。
  • 變數(Variable):一個用來儲存數值的「盒子」,隨著算法執行,裡面的值會改變(例如:「令 \(i = i + 1\)」意思是更新標記為 \(i\) 的盒子裡的數值)。
  • 有限性(Finite):這點至關重要!算法必須在有限步驟內結束,不能無限執行下去。

類比:想像你在教一台機器人泡茶。你不能只說「泡茶」,你必須說:1. 把水煮沸。2. 將茶包放入杯中。3. 倒水。如果你忘了叫它停止倒水,你的廚房就會淹水了!這就是為什麼終止(Termination)是算法的核心。

快速回顧:一個算法必須有清晰的開始、明確的步驟,以及確定的結束點。

2. 跟著地圖走:流程圖與偽代碼

算法通常以兩種主要方式呈現:流程圖(Flowcharts)(視覺化地圖)和偽代碼(Pseudocode)(類似英語的指令)。

需要記住的流程圖符號:

  • 橢圓形:開始或結束。
  • 矩形:處理或指令(例如:「將 \(x\) 加 1」)。
  • 菱形:決策或「如果(if)」語句(例如:「\(x > 10\) 嗎?」)。這類符號總有兩條路徑出來:「是」或「否」。

理解邏輯:

算法經常使用迭代過程(Iterative processes)(循環)。這意味著重複執行一組步驟,直到滿足特定條件為止。
範例:「當水尚未煮沸時,持續加熱水壺。」

記憶小撇步:在偽代碼中,片語「令 \(i = i + 1\)」非常常見。不要把它當成代數方程式(那樣 \(i\) 就會消掉了!),要把它想成一條指令:「用新值(舊值 + 1)來取代 \(i\) 的舊值。」

總結:流程圖適合視覺型學習者;偽代碼適合喜歡列表的人。兩者完成的工作是一樣的!

3. 算法複雜度:電腦運作得有多辛苦?

並非所有算法都生而平等。有些算法速度很快,有些則在問題規模變大時非常緩慢。我們使用複雜度(Complexity)來衡量這一點。

「大 O」符號(Big O Notation)

我們使用階數符號(Order Notation)(例如 \(O(n)\) 或 \(O(n^2)\))來描述算法所需的運算時間隨問題規模(\(n\))增長的方式。

  • 線性複雜度 \(O(n)\):如果你將項目數量增加一倍,所需時間也會加倍(例如:逐一搜尋列表)。
  • 二次複雜度 \(O(n^2)\):如果你將項目數量增加一倍,所需時間會變成原來的四倍(\(2^2 = 4\))。當你在一個循環中又套用另一個循環時,就會發生這種情況!

你知道嗎?我們通常關注最壞情況(Worst Case)。這能確保無論輸入的數據有多不理想,我們都知道該算法所需的最長時間。

快速回顧練習:如果一個 \(O(n^2)\) 算法處理 100 個項目需要 5 秒,那麼處理 200 個項目需要多久?
規模翻倍(\(\times 2\)),因此時間增加 \(2^2 = 4\) 倍。
新時間 = \(5 \times 4 = 20\) 秒。

4. 排序算法:將事物按順序排列

課程大綱特別強調了快速排序(Quick Sort)算法。這是一種「分治法(Divide and Conquer)」的排序方式。

快速排序如何運作:

  1. 選擇一個樞紐(Pivot)(通常是列表中的第一個或最後一個項目)。
  2. 將其他所有項目與樞紐進行比較。
  3. 將小於樞紐的項目移至左側,大於樞紐的項目移至右側。
  4. 現在樞紐已經位於其最終正確的位置
  5. 對左側和右側的「子列表」重複上述過程。

常見錯誤:當手動進行快速排序時,學生常會忘記一旦樞紐被選中並用於拆分列表後,該樞紐就已經「鎖定」在位了。下次再進行拆分時,千萬別再移動它!

要點:像快速排序這樣的排序算法,其最壞情況的複雜度通常為 \(O(n^2)\)

5. 裝箱算法與啟發式方法

有時候,找到「完美」的答案需要太長時間。在現實世界中,「足夠好且快速」往往比「完美但緩慢」更好。這就是啟發式方法(Heuristics)發揮作用的地方。

裝箱問題(Bin Packing):

想像你在把箱子裝進貨車。你希望使用的箱子數量越少越好。

  • 首次適應法(First Fit):按照給出的順序逐個取出物品,放入第一個能裝得下的箱子中。
  • 遞減首次適應法(First Fit Decreasing, FFD):將物品按大小降序排列,然後再使用「首次適應法」。這通常效果更好,因為你先處理了那些大而難裝的物品!
  • 滿箱法(Full Bin):尋找物品組合,使其恰好填滿一個箱子的策略。

重要觀點:這些都是啟發式算法。它們高效且快速(複雜度為 \(O(n^2)\)),但不保證能得到最少箱子數量的絕對最佳解。它們只是給出一個非常好的估算值。

總結:追求速度用「首次適應法」;想要更好的結果用「遞減首次適應法」(但記得要先排序!)。

6. 證明算法

我們如何確定一個算法確實有效?
- 窮舉證明(Proof by Exhaustion):測試每一個可能的案例(只適用於非常小的問題!)。
- 反例否定(Disproof by Counter-example):如果你找到一個算法失敗的案例,就證明該算法是不正確的。

鼓勵:如果這些證明看起來很抽象,別擔心!大多數考試題目只會要求你解釋某個步驟為何有效,或者提供一個簡單的例子,說明為什麼某個啟發式算法無法給出最佳答案。

本章重點小結:
算法是用於提升效率的邏輯工具。透過理解它們的結構(流程圖/偽代碼)、效率(複雜度)以及侷限性(啟發式方法),你就能有系統地建模並解決現實世界中的複雜問題。