章節:演算法設計 — 你的解難指南!
各位同學好!歡迎來到資訊及通訊科技(ICT)其中一個最重要的課題:演算法設計。別被這個聽起來很「高大上」的名字嚇倒。如果你曾跟著食譜煮菜,或者給朋友指路,那麼你其實已經應用了演算法!
在這一章,我們將會學習如何像電腦科學家一樣思考。我們會把問題拆解成電腦能夠理解的簡單邏輯步驟。這項技能超級有用,不僅限於編寫程式,更能幫助你解決生活中的各種問題。準備好成為解難高手了嗎?讓我們開始吧!
演算法到底是什麼?
演算法(Algorithm)是為了解決特定問題或執行某項任務而設計的有限、按部就班的指令集。把它想像成一個完美的食譜。
比喻:烘焙蛋糕
想像你手上有一個朱古力蛋糕的食譜。
- 問題:你想做出一個美味的朱古力蛋糕。
- 輸入:麵粉、糖、雞蛋和可可粉等材料。
- 演算法:食譜中按部就班的指示(1. 預熱焗爐。2. 混合麵粉和糖。3. 加入雞蛋...等等。)。
- 輸出:完成的朱古力蛋糕!
一個好的演算法,就像一個好的食譜一樣,必須清晰、精確,並有一個明確的終點。你不能有一個步驟寫著「加一點糖」——它需要明確地寫著「加 200 克糖」。
重點提示
演算法只是一個清晰的計劃或一套解決問題的規則。它是我們在開始編寫程式之前所撰寫的「操作指南」。
表達演算法:編寫程式的藍圖
在建造房屋之前,建築師會繪製藍圖。同樣地,在我們編寫程式之前,我們也會先制定計劃。我們將學習兩種主要方法來實現這一點:虛擬碼(Pseudocode)和流程圖(Flowcharts)。
1. 虛擬碼(Pseudocode)
虛擬碼意指「偽程式碼」或「假程式碼」。它是一種將演算法以結合日常英語和類似程式語言的語句寫出來的方法。它沒有嚴格的語法規則,因此你可以專注於邏輯,而無需擔心完美的語法。
例子:一個找出兩個數字平均值的演算法。
輸入 數字1
輸入 數字2
總和 = 數字1 + 數字2
平均值 = 總和 / 2
輸出 平均值
看吧?它簡單易讀,清楚地展示了步驟。
2. 程式流程圖(Program Flowcharts)
流程圖是演算法的圖形表示。它使用由箭頭連接的標準符號來顯示邏輯流程。這對於將過程視覺化非常有用。
常見流程圖符號:
- 終端(橢圓形):用於演算法的「開始」和「結束」點。
- 輸入/輸出(平行四邊形):用於從用戶獲取輸入或顯示輸出。
- 處理(長方形):用於任何計算或操作,如加法或賦值。
- 判斷(菱形):用於提出問題(通常有「是」或「否」的答案)。這是演算法分支的地方。
- 流程線(箭頭):連接符號並顯示流程方向。
例子:與上面「兩個數字平均值」演算法相同的流程圖。
(開始)--> [輸入 數字1] --> [輸入 數字2] --> [總和 = 數字1 + 數字2] --> [平均值 = 總和 / 2] --> [輸出 平均值] --> (結束)
(想像這些是正確形狀並由箭頭連接!)
快速回顧
虛擬碼:以簡單、有結構的英文寫出來。
流程圖:使用標準符號繪製出來。
基本構件:資料類型與資料結構
為了解決問題,我們需要處理資料。但電腦需要知道它正在處理什麼類型的資料。它是一個數字?一個字詞?一個真/假值?這就是資料類型(Data Types)的用武之地。
簡單資料類型
課程大綱要求我們掌握四種簡單類型:
- 整數(Integer):沒有小數點的正數或負數。例子:10, -45, 0, 12345。
- 實數(Real):帶有小數點的數字。例子:99.9, 3.14, -0.05。
- 字元(Character):單一字母、數字或符號,以單引號括起來。例子:'A', 'h', '7', '$'。
- 布林值(Boolean):表示一個真值。它只能是兩者之一:真(True)或假(False)。把它想像成一個開關,只能是開或關。
布林邏輯(真/假值的力量)
我們可以使用邏輯運算符組合布林值。你需要知道的三個是AND(和)、OR(或)和NOT(非)。
- AND(和):只有當兩個條件都為真時,結果才為真。
例子:「如果你吃完蔬菜和清潔你的房間,你就可以得到甜品。」(你必須完成兩項!) - OR(或):如果至少一個條件為真,結果就為真。
例子:「如果我考試得到 A 或 B,我就會很高興。」(任何一個都足夠了!) - NOT(非):反轉真值。NOT 真 變為 假,NOT 假 變為 真。
例子:如果「isRaining」(正在下雨)為真,那麼「NOT isRaining」(沒有下雨)就為假。
我們經常使用真值表(truth tables)來查看所有可能的結果:
AND 的真值表
A AND B 為真嗎?
A=真, B=真 --> 真
A=真, B=假 --> 假
A=假, B=真 --> 假
A=假, B=假 --> 假
OR 的真值表
A OR B 為真嗎?
A=真, B=真 --> 真
A=真, B=假 --> 真
A=假, B=真 --> 真
A=假, B=假 --> 假
簡單資料結構
有時我們需要將資料組合起來。這就是資料結構的作用。
-
字串(String):一連串的字元。基本上,任何文字、單詞或句子。
例子:「Hello World」、「HKDSE ICT」、「Student123」。 -
一維陣列(One-Dimensional Array):一列相同資料類型的項目。想像它像一個編號的儲物櫃列表或一個雞蛋紙盒。每個項目都有一個位置(稱為索引),通常從 0 開始。
例子:一個名為 `scores` 的陣列,用於儲存 3 個考試成績:`[95, 88, 72]`。這裡,`scores[0]` 是 95,`scores[1]` 是 88,依此類推。
重點提示
選擇正確的資料類型(整數、實數等)和結構(如陣列)是設計一個良好演算法的至關重要的第一步。
控制流程:三種基本結構
令人驚訝的是,任何演算法,無論多麼複雜,都可以僅使用三種基本控制結構來構建。讓我們掌握它們吧!
你知道嗎?這個概念是「結構化程式定理」的一部分,這是電腦科學中的一個基本原則,它證明了這三種結構足以解決任何可計算問題!
1. 順序結構(Sequence)
這是最直接的結構。指令按照它們書寫的順序一個接一個地執行。沒有步驟被跳過,也沒有分支。
我們的「兩個數字平均值」演算法就是一個完美的順序結構例子。
2. 選擇結構(Selection)
這與做出選擇有關。演算法根據條件是真還是假來遵循不同的路徑。這是通過 IF-THEN-ELSE(如果-那麼-否則)邏輯來完成的。
-
二元選擇(IF-ELSE):有一個條件和兩個可能的路徑。
虛擬碼例子:
輸入 分數
如果 分數 >= 50 那麼
輸出 「合格」
否則
輸出 「不合格」
結束如果 -
多重選擇:當有兩個以上可能的路徑時使用。你可以使用多個 IF-ELSEIF 語句來實現。
虛擬碼例子:
輸入 分數
如果 分數 >= 80 那麼
輸出 「A 級」
否則如果 分數 >= 60 那麼
輸出 「B 級」
否則
輸出 「C 級」
結束如果
3. 重複結構(Iteration,即循環/迴圈)
這是用於重複執行一組指令多次。這也稱為循環(looping)。
比喻:想像你要洗 10 個碗碟。你對每個碗碟重複相同的過程(擦洗、沖洗)。這就是一個循環!
虛擬碼例子:一個循環,用於列印數字 1 到 5。
對於 計數器 從 1 到 5
輸出 計數器
結束對於
這將輸出:1, 2, 3, 4, 5。
重點提示
每個演算法都是順序結構(按順序做事)、選擇結構(做出選擇)和重複結構(重複做事)的組合。
測試你的演算法:它會奏效嗎?
建立演算法很棒,但我們如何知道它是正確的呢?我們需要測試它!我們不能只抱著「最好會成功」的心態;我們必須積極地找出錯誤。
手動追蹤與追蹤表
手動追蹤(Dry run)是使用一組測試資料,手動逐步執行你的演算法,假裝你就是電腦。組織手動追蹤的最佳方式是使用追蹤表(trace table)。
追蹤表是一個表格,它追蹤演算法中每個變數在每個步驟的值。這絕對是找出邏輯錯誤最強大的工具!
循序漸進的例子:使用追蹤表
演算法目的:找出列表中最大的數字。列表為 `[5, 8, 3]`。
虛擬碼:
1. 數字列表 = [5, 8, 3]
2. 最大值 = 數字列表[0]
3. 對於 i 從 1 到 2
4. 如果 數字列表[i] > 最大值 那麼
5. 最大值 = 數字列表[i]
6. 結束如果
7. 結束對於
8. 輸出 最大值
追蹤表:
| 步驟 | i | numbers[i] | 條件:numbers[i] > largest | largest | | :--- | :-: | :---: | :---: | :---: | | 1-2 | - | - | - | 5 | | 3 | 1 | 8 | 8 > 5 為真 | 5 | | 4-5 | 1 | 8 | 真 | 8 | | 3 | 2 | 3 | 3 > 8 為假 | 8 | | 4 | 2 | 3 | 假 | 8 | | 7 | - | - | - | 8 | | 8 | - | - | - | 輸出:8 |透過追蹤這些值,我們可以清楚地看到 `largest` 是如何從 5 變成 8 的,並且我們可以確認最終輸出是正確的。
找出邏輯錯誤
邏輯錯誤(logic error)是演算法設計中的錯誤,即使程式可以運行而不會崩潰,它也會產生不正確的結果。
例子:如果我們在條件中寫成 `numbers[i] < largest`,追蹤表就會向我們展示演算法正在尋找最小的數字,而不是最大的。
常見的錯誤要避免
要小心循環計數器和陣列索引!一個常見的錯誤是「差一」錯誤("off-by-one" error),即循環多運行一次或少運行一次。追蹤表非常適合捕捉這種錯誤!
構建大型專案:模組化的力量
如果你有一個非常大、複雜的問題,例如構建一個完整的應用程式,該怎麼辦?嘗試將所有內容寫成一個巨大的演算法將會是一場惡夢!
解決方案就是模組化(modularity)。這意味著將一個大問題分解成更小、更簡單、更易於管理的小問題,稱為模組(modules)。
比喻:製造汽車
你不會一次過製造一整輛汽車。你會為引擎、車身、車輪和電子設備等設置不同的團隊。每個部分都是一個模組。它們會被獨立地製造和測試,最後再組裝起來。
模組化的優點:
- 更容易理解:小模組比一大塊程式碼更容易閱讀和管理。
- 更容易測試和偵錯:你可以單獨測試每個模組,確保它完美運行,然後再將其與其他模組組合。
- 可重用:你經常可以在許多不同的程式中重複使用一個模組(例如用於計算稅款的模組)。
- 團隊合作:不同的程式員可以同時處理不同的模組。
重點提示
對於任何複雜的問題,總是思考:「我如何將其分解成更小的部分?」這種模組化的方法是成功解決問題的關鍵。