讓我們一起來談談編程!

大家好!歡迎來到精彩的編程世界。即使你從未寫過一行程式碼,也請不用擔心。把編程想像成學習一種新語言,用來與電腦溝通。你不再說「請」,而是使用特定的指令來確切地告訴電腦該做什麼。

在本章中,我們將學習如何像解難者一樣思考、規劃解決方案、編寫電腦指令,甚至找出並修正錯誤。這是一項超有用的技能,不只適用於資訊及通訊科技科,更能應用於解決現實生活中各種各樣的問題。讓我們開始吧!



1. 從問題到計劃:先思考,後編碼

在你告訴電腦該做什麼之前,你需要一個清晰的計劃。優秀的程式員花在思考和規劃上的時間,比輸入程式碼的時間更多。這個規劃階段稱為運算思維 (Computational Thinking)

a. 理解問題

第一步始終是理解你需要達成什麼目標。

我們將其分為三個部分:

輸入 (Input):程式開始時需要什麼資訊?(例如:要相加的兩個數字)
處理 (Process):程式需要採取哪些步驟?(例如:相加數字的動作)
輸出 (Output):程式最終應顯示什麼結果?(例如:兩個數字的總和)

想像你正在煮即食麵。
輸入:麵、熱水、調味包。
處理:1. 打開蓋子。2. 加入調味料。3. 倒水。4. 等待3分鐘。
輸出:一碗美味的麵條!

有時候,一個問題可能太大。所以我們使用拆解問題 (decomposition) — 將大問題分解成更小、更易於管理的小問題。解決許多小問題,遠比解決一個巨大問題要容易得多。

b. 設計演算法

演算法 (algorithm) 只是解決問題的一系列步驟說明,一個比較專業的術語。它是你給電腦的「食譜」。在我們編寫程式碼之前,有兩種常用方法來記錄我們的演算法。

虛擬碼

虛擬碼 (Pseudocode) 意指「假的程式碼」。這是一種使用簡單英語來寫出演算法的方式,但其結構看起來有點像真實的程式編寫。它沒有嚴格的規則,但能幫助你組織思緒。

例子:找出兩個數字平均值的演算法。
1. 從使用者取得第一個數字(我們稱之為 Num1)。
2. 從使用者取得第二個數字(我們稱之為 Num2)。
3. 將 Num1 和 Num2 相加來計算總和 (Sum)。
4. 將總和 (Sum) 除以 2 來計算平均值 (Average)。
5. 向使用者顯示平均值 (Average)。

程式流程圖

流程圖 (flowchart) 是一種使用標準符號來表示演算法的視覺化方法。它幫助你「看見」程式的流程。

常用符號:

橢圓形 (終止符):用於表示「開始」和「結束」點。
平行四邊形 (輸入/輸出):用於獲取輸入或顯示輸出。
矩形 (處理):用於計算或賦值等動作。
菱形 (判斷):當程式需要做出選擇時使用(例如:IF 語句)。它總是會有兩個輸出路徑:「是」和「否」。
箭頭 (流程線):顯示程式流程的方向。

乾跑與追蹤表

你如何知道你的演算法是否有效,甚至不用編寫程式碼?你可以假裝自己是電腦!這稱為乾跑 (dry run)

追蹤表 (trace table) 幫助你記錄演算法每一步驟中變數的值。這是找出邏輯錯誤的一項重要技能。

重點提示:在編寫任何實際程式碼之前,請務必使用虛擬碼或流程圖等工具來規劃你的解決方案。一個好的計劃能為你節省大量時間!




2. 程式的基石:變數、資料與運算子

程式與資料協同運作。為了處理資料,我們需要將它儲存在某處並給予一個名稱。這就是變數和常數發揮作用的地方。

a. 變數與常數

變數 (variable) 就像一個有標籤的盒子,你可以將資訊儲存在裡面。盒子裡的資訊可以隨時改變。例子:`userScore`(使用者分數)、`age`(年齡)、`name`(姓名)。

常數 (constant) 是一個內容設定一次後就永遠不能更改的盒子。例子:`PI = 3.14159`(圓周率π)、`MAX_ATTEMPTS = 3`(最大嘗試次數)。

b. 資料類型

電腦需要知道你正在儲存的是哪資料。這稱為資料類型 (data type)

整數 (Integer):儲存整數。(例如:10, 0, -99)
實數 / 浮點數 (Real / Float):儲存帶有小數點的數字。(例如:98.6, 3.14, -0.05)
字元 (Character):儲存單個字母、數字或符號。(例如:'A', '7', '$')
字串 (String):儲存一串字元(文字)。(例如:「Hello World」、「陳先生」)
布林值 (Boolean):只能有兩個值:真 (True)假 (False)。它就像一個電燈開關:開或關。

快速回顧:選擇資料類型
你的年齡? -> 整數
一杯飲料的價格? -> 實數<
你的成績(A, B, C)? -> 字元
你的名字? -> 字串
門是開著的嗎? -> 布林值

c. 簡單資料結構:陣列

陣列 (array)(或列表)是相同資料類型的項目集合,它們儲存在一起。把它想像成一排儲物櫃或一個雞蛋紙盒。每個「儲物櫃」都有一個索引號碼,以便你可以直接存取它。

例子:一個名為 `scores` 的陣列,用來儲存5位學生的測驗分數。
`scores` = [85, 92, 78, 66, 95]

要取得第二位學生的分數,你可能會使用 `scores[1]` (在許多程式語言中,索引是從0開始的!)。

d. 運算子:動作詞

運算子是用於對資料執行操作的符號。

算術運算子 (Arithmetic Operators):用於數學運算!`+`(加)、`-`(減)、`*`(乘)、`/`(除),以及 `mod`(取模運算,返回除法的餘數。例如:10 mod 3 的結果是 1)。

關係運算子 (Relational Operators):用於比較事物。它們的結果總是一個布林值(真/假)。
`==`(等於)、`!=` 或 `<>`(不等於)、`>`(大於)、`<`(小於)、`>=`(大於或等於)、`<=`(小於或等於)。

布林 (邏輯) 運算子 (Boolean (Logical) Operators):用於組合真/假條件。
AND(與):兩個條件都必須為真。(例如:`age > 18 AND hasTicket == True`)
OR(或):至少一個條件必須為真。(例如:`day == "Saturday" OR day == "Sunday"`)
NOT(非):反轉值。(例如:`NOT isRaining`)

重點提示:變數儲存資料。每項資料都有一個類型。運算子讓你能夠對該資料執行數學運算、比較和邏輯檢查等動作。




3. 控制流程:做出決策和重複動作

程式並非總是從上到下執行。我們需要使用控制結構 (control structures) 來控制其執行路徑。

a. 順序結構

這是預設的流程。指令按照它們編寫的順序一個接一個地執行。簡單直接。

1. 取得輸入。
2. 進行計算。
3. 顯示輸出。

b. 選擇結構(做出選擇)

當程式需要做出決策時,就會使用這種結構。我們使用 IF-THEN-ELSE(如果-那麼-否則)語句。

比喻:「如果下雨,那麼我會帶傘,否則我會戴太陽眼鏡。」

二元選擇 (IF-ELSE):在兩條路徑之間做出簡單選擇。
多重選擇 (IF-ELSEIF-ELSE):用於在兩個以上選項之間進行選擇。
例子:
如果分數 >= 80 那麼顯示「優秀」
否則如果分數 >= 60 那麼顯示「良好」
否則顯示「有待改進」

c. 重複結構(重複動作)

重複結構 (Iteration),或稱為迴圈 (loops),用於重複執行一段程式碼多次。這非常有用!

計數控制迴圈 (FOR 迴圈):當你清楚知道要重複某件事多少次時,就使用這種迴圈。
例子:「重複10次:拍手。」
`FOR i FROM 1 TO 10`
` PRINT "拍手!"`
`ENDFOR`

條件控制迴圈 (WHILE 迴圈):當你希望只要某個條件為真就重複執行時,就使用這種迴圈。你可能不知道需要重複多少次。
例子:「當杯子未滿時,繼續倒水。」
`WHILE 密碼不正確`
` 再次要求使用者輸入密碼`
`ENDWHILE`

巢狀迴圈 (Nested Loops)(進階):這是一個迴圈套在另一個迴圈裡面。內層迴圈會在每執行一次外層迴圈時,完成其所有的重複次數。
想像一個時鐘:秒針(內層迴圈)跳動60次,分針(外層迴圈)才剛好跳動一次。

重點提示:三種基本的控制結構是順序結構 (Sequence)(一步一步執行)、選擇結構 (Selection)(使用 IF 進行選擇)和重複結構 (Iteration)(使用迴圈進行重複)。掌握這些是程式編寫的關鍵!




4. 進階演算法與資料結構

一旦你掌握了基礎知識,你就可以開始使用標準、經過驗證的演算法和更有組織的資料結構來解決更複雜的問題。

a. 搜尋演算法

你如何在一個列表(陣列)中找到特定項目?

循序搜尋 (Linear Search)

這是一種簡單、暴力破解的方法。你從列表的開頭開始,逐一檢查每個項目,直到找到你要找的,或者到達列表的末尾。
優點:超級容易實現。適用於任何列表,無論是否排序。
缺點:如果列表很長,可能會非常慢。

比喻:在一個完全沒有整理的書架上,從左到右逐一檢查每本書的標題,來尋找一本特定的書。

二分搜尋 (Binary Search)

這是一種快得多、「分而治之」的方法。重要:它只適用於已排序的列表。
1. 查看列表的中間項目。
2. 如果是你要的項目,你就完成了!
3. 如果你要的項目較小,你可以忽略列表的整個後半部分。
4. 如果你要的項目較大,你可以忽略列表的整個前半部分。
5. 對剩餘的部分重複此過程,直到找到該項目。
優點:速度極快,即使對於非常大的列表也一樣。
缺點:列表必須先經過排序。

比喻:在字典中查一個單字。你不會從「A」開始查起;你會翻到中間,發現翻過頭了,然後再集中搜尋前半部分。

b. 排序演算法

排序意指將一列表的項目按照特定順序(例如:升序或降序)排列。

氣泡排序 (Bubble Sort)

這種演算法會重複遍歷列表,比較相鄰項目,如果它們的順序不正確就交換它們。這個過程重複進行,直到列表排序完成。
比喻:較大的數字會像水中的氣泡一樣,慢慢地「浮」到列表的末端。它易於理解,但效率不高。

插入排序 (Insertion Sort)

這種演算法一次一個項目地建立最終的排序列表。它從輸入列表中取出每個項目,並將其「插入」到列表中已排序部分的正確位置。
比喻:就像你整理一副撲克牌一樣。你一次拿起一張牌,然後將它放入你已經拿在手中的牌中正確的位置。

選擇排序 (Selection Sort)

這種演算法將列表分成已排序和未排序兩部分。然後它會重複地從未排序部分找出最小(或最大)的元素,並將其移動到已排序部分的末尾。
比喻:在隊伍中找到最矮的人並將他移到最前面。然後從剩下的人中找到次矮的,將他移到第二個位置,依此類推。

c. 堆疊與佇列(作為陣列)

這些是在列表中管理資料的方式,對增添和移除項目有特定的規則。

堆疊 (Stack)

遵循 LIFO 原則:後進先出 (Last-In, First-Out)
• 你只能將新項目加入到頂部(稱為推入 (push))。
• 你只能從頂部移除項目(稱為彈出 (pop))。
比喻:一疊盤子。你把一個乾淨的盤子放在最上面,然後你從最上面取走一個盤子。最底下的盤子是第一個放進去的,但它將是最後一個被取出來的。

佇列 (Queue)

遵循 FIFO 原則:先進先出 (First-In, First-Out)
• 新項目會被加入到尾部(稱為入佇列 (enqueue))。
• 項目會從頭部被移除(稱為出佇列 (dequeue))。
比喻:等巴士的隊伍。第一個排隊的人是第一個上巴士的人。

重點提示:知道正確的演算法(例如用於排序列表的二分搜尋)可以讓你的程式運行得更快。堆疊和佇列是簡單但強大的組織資料方式,它們帶有存取規則。




5. 程式碼組織與風格

編寫好的程式碼不只是讓它能運行。它還包括讓程式碼整潔、易於閱讀和管理。

a. 模組化:子程式

與其編寫一個龐大的程式,不如將其分解成更小、獨立的迷你程式,稱為子程式 (sub-programs)(或函數 (functions)/程序 (procedures))。每個子程式只負責一個特定的任務。

模組化的優點:
更容易閱讀:一個調用幾個命名良好子程式的主程式會更容易理解。
更容易除錯:如果計算稅款出現問題,你只需要檢查 `calculateTax()` 這個子程式。
程式碼重用:你可以在許多不同的地方使用相同的子程式,而無需重複編寫程式碼。

b. 參數傳遞

參數 (parameter) 是一種你「傳遞」給子程式以幫助它完成工作的資訊。
例子:在子程式 `calculateArea(length, width)` 中,`length` 和 `width` 就是參數。你給它數字,它會回傳面積給你。

c. 變數作用域:區域變數與全域變數

區域變數 (Local Variables):這些變數宣告在子程式*內部*。它們只存在於該子程式內,也只能在該子程式內使用。這是一個良好的實踐,因為它可以防止程式其他部分意外地更改變數。

全域變數 (Global Variables):這些變數在程式頂部宣告,可以從*任何地方*存取和更改。它們可能很有用,但也可能使你的程式難以除錯。請謹慎使用!

d. 檔案處理

變數將資料儲存在記憶體 (RAM) 中,這是暫時的。當程式結束時,資料就會遺失。為了永久儲存資料,我們使用檔案 (files)。你可以編寫程式來:
開啟一個文字檔。
• 從檔案中讀取資料。
• 將新資料寫入檔案。
• 將資料附加到檔案末尾。
修改刪除檔案中的記錄。
關閉檔案(非常重要!)。

e. 良好程式編寫風格

這讓你的程式碼對你(將來)和對其他人來說都更容易理解。
有意義的命名:使用 `studentAge` 而不是 `x`。使用 `calculateAverage()` 而不是 `doStuff()`。
註解:在你的程式碼中留下簡短的註釋,解釋複雜的部分。電腦會忽略它們。
縮排和間距:使用一致的縮排(Tab 鍵或空格)來顯示程式碼的結構,尤其是在迴圈和 IF 語句內部。這對可讀性有巨大的影響!

重點提示:將大程式分解成更小的子程式。盡可能使用區域變數。編寫整潔、註解清晰的程式碼。這是送給未來自己的禮物!




6. 找出並修正錯誤:測試與除錯

從初學者到專家,每個程式員都會產生錯誤(bugs)。這是程式編寫過程中正常的一部分!關鍵的技能在於找出它們(測試)並修正它們(除錯)。

a. 程式錯誤的類型

語法錯誤 (Syntax Errors)

這些是你程式碼中的「文法」錯誤。你違反了程式語言的規則,例如拼錯指令或忘記了一個括號。
如何發現:電腦通常會拒絕運行你的程式,並會給你一個錯誤訊息,通常會指向錯誤所在的行。
比喻:用英文寫「The cat chase mouse」(貓追老鼠)。文法是錯的。

邏輯錯誤 (Logic Errors)

這些是最棘手的錯誤。程式運行得非常順利,沒有崩潰,但它給出的答案是錯誤的,或做了錯誤的事情。電腦正在完全按照你告訴它的去做,但你的指令在邏輯上有缺陷。
如何發現:你需要使用不同的輸入來測試你的程式,並檢查輸出是否正確。追蹤表是找出這些錯誤的最佳幫手!
比喻:一個食譜告訴你加一湯匙鹽而不是一茶匙鹽。食譜照樣能執行,但結果會很難吃。

執行階段錯誤 (Run-time Errors)

這些是程式*運行時*發生的錯誤。語法是正確的,但程式被要求做一些不可能的事情,導致其崩潰。
例子:試圖將一個數字除以零,或者試圖存取陣列中不存在的項目(例如:要求取得一個只有5個項目的列表中的第10個項目)。
比喻:完美地跟隨地圖指示,但指示卻讓你開車衝下懸崖。

b. 測試你的程式

為了找出錯誤,你必須使用一套良好的測試數據 (test data) 來測試你的程式碼。

正常數據:合理、預期的輸入,以查看程式是否正確運行。
極端數據:可能的最大和最小有效值。
邊界數據:恰好在允許範圍邊緣的值。這些對於找出錯誤非常重要!對於像 `age >= 18` 這樣的條件,你應該測試17、18和19。
無效數據:應該被拒絕的數據(例如:輸入「hello」作為你的年齡)。

c. 除錯 (Debugging)

除錯是修正錯誤的藝術。以下是一些技巧:

人工追蹤:使用追蹤表逐行檢查你的程式碼,就像你檢查演算法一樣。 • 輸出語句(標記):在你的程式碼中添加臨時的打印語句,以顯示變數在不同點的值。這有助於你「看到」內部發生了什麼。 • 斷點:許多程式設計環境中的工具,讓你可以將程式暫停在特定的程式碼行。然後你可以檢查所有變數的狀態。

重點提示:錯誤是正常的。學習識別三種主要類型:語法錯誤、邏輯錯誤和執行階段錯誤。徹底測試你的程式碼,特別是使用邊界數據,以找出錯誤。使用除錯工具來修正它們。




7. 程式編寫在現實世界中的應用

程式編寫不只用於計算機和網站。它還用於與實體世界互動!

a. 與硬體互動

現代程式編寫通常涉及使用預先編寫的程式碼集合,稱為程式庫 (libraries)模組 (modules)。這些程式庫提供了簡單的指令,用於與以下硬體互動:
感應器 (Sensors):從光線感應器、溫度感應器或加速規(檢測運動)讀取數據。
致動器 (Actuators):控制馬達、LED 或揚聲器等裝置。

b. 事件驅動編程

許多現代應用程式並非從起始點運行到終點。相反,它們等待某些事情發生。這稱為事件驅動編程 (event-driven programming)

事件 (event) 是一種動作,例如使用者點擊按鈕、計時器響起或感應器偵測到某些東西。
事件處理器 (event handler) 是一段特定的程式碼,當特定事件發生時會運行。

比喻:一部自動售賣機。它坐著等待(什麼都不做),直到「使用者按下按鈕」這個事件發生。當事件發生時,「派發飲料」的事件處理器程式碼就會運行。

圖形使用者介面 (GUIs)、智能手機應用程式和機械人技術就是這樣運作的!

重點提示:程式編寫可以使用程式庫和事件驅動的方法,來連接軟件和實體世界,讓程式對感應器輸入或使用者動作等事件作出反應。