鄭士康 國立台灣大學 電機工程學系/電信工程研究所/ 資訊網路與多媒體研究所 流程控制 鄭士康 國立台灣大學 電機工程學系/電信工程研究所/ 資訊網路與多媒體研究所
綱要 巢狀if 與if-else if敘述 switch 敘述 列舉型別 for 迴圈 while 迴圈 do-while 迴圈 continue與break
綱要 變數生命週期與有效範圍 無窮迴圈應用 結構化程式設計 應用虛擬碼設計結構化程式
綱要 巢狀if 與if-else if敘述 switch 敘述 列舉型別 for 迴圈 while 迴圈 do-while 迴圈 continue與break
巢狀if流程 true false true false score < 60 score < 80 輸出”不及格” 輸出”成績優良” 輸出”成績中等”
UsingNestedIf.Program片段 if (score < FAIL_THRESHOLD) { Console.WriteLine("請注意, 成績不及格"); } else if (score < GOOD_GRADE_THRESHOLD) Console.WriteLine("成績中等"); Console.WriteLine("成績優良");
懸置else if ( score >= 60 ) if( score >= 80 ) Console.WriteLine(“成績優良”); else Console.WriteLine(“請注意, 成績不及格”); ============================================
避免懸置else if ( score >= 60 ) { if( score >= 80 ) Console.WriteLine(“成績優良”); } else Console.WriteLine(“請注意, 成績不及格”);
if-else if 敘述 false false true false true false true true score >= 90 false score >= 80 true false score >= 70 true false score >= 60 true true grade = ‘F’ grade = ‘D’ grade = ‘C’ grade = ‘B’ grade = ‘A’
UsingIfElseIf.Program片段 if (score >= 90) { grade = ‘A’; } . . . . . . else if (grade >= 60) grade = ‘D’; else grade = ‘F’;
練習 西元年份被4整除, 但不被100整除,就是閏年;能被400整除的話, 也算閏年 寫一個程式,輸入西元年份,輸出該年是否閏年 可以先畫流程圖澄清概念
綱要 巢狀if 與if-else if敘述 switch 敘述 列舉型別 for 迴圈 while 迴圈 do-while 迴圈 continue與break
同一變數之有限多個值作為條件之連續判斷 false false true false true false true false true grade == ‘A’ false grade == ‘B’ true false grade == ‘C’ true false grade == ‘D’ true false grade == ‘F’ true true 輸出 “成績錯誤” 輸出 “不及格” 輸出 “成績尚可” 輸出 “成績中等” 輸出 “成績良好” 輸出 “成績優異”
Switch 流程 default ‘F’ ‘D’ ‘C’ ‘B’ ‘A’ grade 輸出 “成績錯誤” 輸出 “不及格” 輸出 “成績尚可” 輸出 “成績中等” 輸出 “成績良好” 輸出 “成績優異”
UsingSwitch.Program 片段(1/2) Console.Write("請輸入成績:A, B, C, D, F: "); char grade = Console.ReadLine().ToCharArray()[0]; switch (grade) { case 'A': Console.WriteLine("成績優異"); break; case 'B': Console.WriteLine("成績良好");
UsingSwitch.Program 片段(2/2) case 'C': Console.WriteLine("成績中等"); break; case 'D': Console.WriteLine("成績尚可"); case 'F': Console.WriteLine("不及格"); default: Console.WriteLine("成績錯誤"); }
switch 流程 true break false break true false true break false break grade==‘A’ 輸出”成績優異” false break grade==‘B’ true 輸出”成績良好” false grade==‘C’ true break 輸出”成績中等” false break grade==‘D’ true 輸出”成績尚可” false grade==‘F’ true break 輸出”成績錯誤” 輸出”不及格” false
switch 敘述 省略break的場合 使用字元與其他整數型別的switch敘述
綱要 巢狀if 與if-else if敘述 switch 敘述 列舉型別 for 迴圈 while 迴圈 do-while 迴圈 continue與break
示範程式UsingEnum重要片段(1/2) enum WeekDay { SUN = 1, MON = 2, TUE = 3, WED = 4, THU = 5, FRI = 6, SAT = 7 }
示範程式UsingEnum重要片段(2/2) WeekDay day = WeekDay.TUE; switch (day) { case WeekDay.SUN: Console.WriteLine("星期日為一週的第{0}天!!", (int)WeekDay.SUN); break; case WeekDay.TUE: Console.WriteLine("星期二為一週的第{0}天!!", (int)WeekDay.TUE); default: Console.WriteLine("一週的第{0}天!!", (int)day); }
列舉型別 (Enumeration) 組織整數常數與程式維護 省略數值指定 應用列舉型別
練習 宣告並測試列舉型別Season,其中包括常數Spring、Summer、Fall、Winter
練習 宣告列舉型別Grade,其可能值包括A、B、C、D、F 成績變數grade宣告為Grade型別,其值由Grade.A到Grade.F 以列舉型別改寫程式UsingSwitch.Program
綱要 巢狀if 與if-else if敘述 switch 敘述 列舉型別 for 迴圈 while 迴圈 do-while 迴圈 continue與break
1加到10 int sum = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10; int sum = 0;
1加到100 int sum = 1 + 2 + 3 + 4 + . . . + 100; int sum = 0; sum += 1;
1加到100的流程 sum = 0 i> 100 i = 1 i <= 100 ++i i <= 100 sum += i
UsingFor.Program 片段 int sum = 0; for (i = 1; i <= 100; i++) { sum += i; } Console.WriteLine( "1 ~ 100 的加總等於 " + sum);
練習 修改範例程式UsingFor,計算1到100的偶數和
關於迴圈(Loops) 迴圈之基本要素 控制變數初值設定 檢驗條件 控制變數改變 常見錯誤 邊界值錯誤, Off-by-one 無窮迴圈
MTable.Program片段 for (i = 1; i < 10; ++i) { for (j = 1; j < 10; ++j) Console.Write("{0}*{1}={2} ", i, j, i * j); } // 印完一組便換行 Console.WriteLine();
迴圈執行效率 迴圈中不改變的敘述 編譯建置過程的最佳化 兩種版本的CIL檔 Release Debug
綱要 巢狀if 與if-else if敘述 switch 敘述 列舉型別 for 迴圈 while 迴圈 do-while 迴圈 continue與break
1加到100的流程 sum = 0 i = 1 false i <= 100 true sum += i ++i 輸出 sum
UsingWhile.Program 片段 int sum = 0; int i = 0; while (i <= 100) { } Console.WriteLine( "1 ~ 100 的加總等於 “ + sum);
常見錯誤 控制變數未設初值 迴圈內控制變數未改變 無窮迴圈
使用時機 迴圈繼續執行之條件比較複雜 很不容易以一個控制變數表現迴圈繼續執行之條件 例如,檔案讀取未結束
綱要 巢狀if 與if-else if敘述 switch 敘述 列舉型別 for 迴圈 while 迴圈 do-while 迴圈 continue與break
1加到100的流程 sum = 0 i = 1 sum += i ++i false i <= 100 true 輸出 sum
UsingDoWhile.Program 片段 int sum = 0; int i = 1; do { sum += i; ++i; } while (i <= 100); Console.WriteLine( "1 ~ 100 的加總等於 “+sum);
for, while, do-while的主要差別
綱要 巢狀if 與if-else if敘述 switch 敘述 列舉型別 for 迴圈 while 迴圈 do-while 迴圈 continue與break
畢氏數 x2 + y2 = z2 前10組畢氏數 (3, 4, 5)、(5, 12, 13)、(6, 8, 10)、(7, 24, 25)、(8, 15, 17)、(9, 12, 15)、(9, 40, 41)、(10, 24, 26)、(11, 60, 61)、(12, 16, 20)
Pythagoras.Program重要片段 for (x = 1; x <= 100; ++x) { for (y = x; y <= 100; ++y) { for (z = 1; z <= 150; ++z) { if (x * x + y * y == z * z) { ++n; if (n <= 10) { Console.WriteLine( "{0}: {1}*{1} + {2}*{2} = {3}*{3}", n, x, y, z); }
UsingBreak.Program重要片段 for (x = 1; x <= 100; ++x) { for (y = x; y <= 100; ++y) { for (z = 1; z <= 150; ++z) { if (x * x + y * y == z * z) { ++n; Console.WriteLine( "{0}: {1}*{1} + {2}*{2} = {3}*{3}", n, x, y, z); break; } if (n == 10) break;
UsingContinueAndBreak.Program片段 for (x = 1; x <= 100; ++x){ for (y = x; y <= 100; ++y){ for (z = 1; z <= 150; ++z){ if (x * x + y * y != z * z) continue; ++n; Console.WriteLine( "{0}: {1}*{1} + {2}*{2} = {3}*{3}", n, x, y, z); break; } if (n == 10) break;
綱要 變數生命週期與有效範圍 無窮迴圈應用 結構化程式設計 應用虛擬碼設計結構化程式
VarScope片段 Console.Write("請輸入一個字元: "); string s = Console.ReadLine(); if (s == "A") { string s1 = s; Console.WriteLine(s1 + "為第一個英文字母!!"); } else { Console.WriteLine(s1 + "不是第一個英文字母!!"); } for (int i = 0; i < 10; i++) { Console.WriteLine(s1);
綱要 變數生命週期與有效範圍 無窮迴圈應用 結構化程式設計 應用虛擬碼設計結構化程式
CheckingInput.Program 片段 Console.Write("輸入成績: "); grade = Convert.ToInt16(Console.ReadLine()); while (grade <0 || grade > 100) { Console.Write("成績須在0到100之間, 請重新輸入: "); } Console.WriteLine("成績為: " + grade);
特設之無窮迴圈 for ( ; ; ) { . . . . . . } 或 while (true) {
UsingInfiniteLoop.Program 片段 int grade = 0; Console.Write("輸入成績: "); while (true) { grade = Convert.ToInt16( Console.ReadLine() ); if (grade >= 0 && grade <= 100) break; // 數值合理則跳出無窮迴圈 Console.Write( "成績須在0到100之間, 請重新輸入: "); } Console.WriteLine("成績為: " + grade);
練習 寫一程式,要求使用者不斷輸入及Echo學生成績,直到輸入為負時為止。印出學生總人數及平均成績
綱要 變數生命週期與有效範圍 無窮迴圈應用 結構化程式設計 應用虛擬碼設計結構化程式
FORTRAN-IV程式片段 SUM = 0 I = 1 100 IF( I > 100 ) GOTO 200 SUM = SUM + I I = I + 1 GOTO 100 200 WRITE(6, 300) SUM 300 FORMAT(1X, I6)
goto敘述 允許使用者由程式某處任意跳到另一處 容易產生通心麵狀程式碼(spaghetti code) 極少數情況下仍需使用
通心麵狀程式碼(Spaghetti Code) 流程
結構化程式
綱要 變數生命週期與有效範圍 無窮迴圈應用 結構化程式設計 演算法虛擬碼
虛擬碼(Pseudo Code) 幫助思考程式流程 沒有程式語言正式,省略細節,易寫易懂 限定使用結構化程式流程控制,容易以程式語言改寫 較流程圖方便 紙筆追蹤測試(Tracing an algorithm)
Euclid 輾轉相除法尋找最大公因數 在正整數x與y都不是0的情況下,持續以較大的數除以較小的數,並將除數與餘數分別設給x與y。最後的x便是原先兩數的最大公因數。
Euclid 輾轉相除法虛擬碼 1. x = 較大的輸入值; 2. y = 較小的輸入值; 3. while( y不等於0) { 3.1 remainder = x 除以y的餘數; 3.2 x = y; 3.3 y = remainder; } 4. 最大公因數 = x;
紙筆測試 GCD(1, 5)=1 GCD(12, 18)=3 GCD(17, 13)=1
Euclid.Program 程式片段 if (x < y) // x 較小時, 需交換x 與 y { int temp = x; y = temp; } while (y != 0) remainder = x % y; y = remainder;
練習 用下一頁的演算法, 撰寫虛擬碼, 進行紙筆測試, 並完成C#程式
判斷是否質數的篩檢法 要判斷x是否質數,可用2開始到x開根號的奇數,逐一檢查是否能整除x 如果都不能整除,x便是質數,否則x就不是質數