決策敘述 4
類的生活方式必須不斷的面對決策問題, 連我家㆒個不到㆔歲的小孩, 也常要思考他手裡的十元是要坐電動車還是買棒棒糖, 程式語言是協助 類解決問題的工具, 當然也有決策敘述 BCB 依決策點的多寡, 分為以 ㆔種決策敘述, 第㆒是單㆒分岐決策的 if, 例如肚子餓了就吃飯 ; 第㆓是雙向分岐決策 if else, 例如肚子餓了就吃飯, 否則繼續前進 ; 第㆔是多向分岐決策的 switch, 例如你身 有 5000 元, 走進㆒家五星級的大飯店用餐, 你的分岐點就很多, 有自助餐 式套餐 日本料理 泰國餐點等等分岐點 本章的重點即是探討 BCB 的決策敘述 4-1 if if 通常用於單㆒分岐的決策, 它的使用時機為 假如 則, 也就是 條件成立時, 則執行某項工作, 但若條件不成立時, 則不予理會 其語法如 : if ( 運算式 ) 敘述區塊 ; 以 語法說明如 : 1. 若運算式的值為 true 則執行敘述區塊, 運算式的值若為 false, 則不會被 執行, 其流程圖如 : ¹Bºâ false true ±Ô z Ï ô 4-2
決策敘述 4 2. 敘述區塊內的敘述若只有㆒個, 則敘述區塊 兩個大括號可予省略 ; 同理若敘述區塊 的大括號遺漏, 則條件成立時, BCB 僅執行敘述區塊的第㆒個敘述, 但更嚴重的問題是敘述區塊的第㆓個以後的敘述, 不論條件成立與否均會自動執行 3. 以 敘述可以判斷變數 a 是否等於 0 if (a==0)? "Game Over"; //? 在本書表示虛擬指令, 印出的意思, // 讀者可使用任意元件替代 範例 4-1a 請輸入㆒個成績, 若此成績大於等於 60 分, 則輸出 及格 題目分析 本例即是單㆒分岐決策的典型範例, 當條件成立時則執行某個敘述 輸出結果 如 圖 4-3
表單配置 如右圖 物件說明 物件 屬性 值 說明 Label Name lblin 輸入提示 Caption 請輸入成績 Edit Name ediscore 輸入成績 Text 68 Label Name lblout 輸出及格與否 Caption Button Name btnstart Caption 開始 Button Name btnend Caption 結束 程式列印 //--------------------------------------------------- void fastcall Tfrm::btnstartClick(TObject *Sender) int a; lblout->caption="" ; a=strtoint(ediscore->text); if (a >=60) 4-4
決策敘述 4 lblout->caption=" 及格 " ; //--------------------------------------------------- void fastcall Tfrm::btnendClick(TObject *Sender) Close(); //--------------------------------------------------- 程式說明 本例的 if 敘述區塊, 僅有㆒個敘述, 所以大括號讀者可自行省略 4-2 if...else ㆒節的 if 僅適合單㆒分岐的決策, 當條件成立時執行某㆒敘述, 當條件未成立時, 則未有任何處置 但在日常生活的領域, 常出現 假如 則, 否則, 此種決策模式有兩種解決問題的方案, 故稱為雙向分岐決策, 此時可使用 if else 敘述, if else 敘述的語法如 : if ( 運算式 ) 敘述區塊 1; else 敘述區塊 2; 以 語法說明如 : 4-5
1. 運算式的值若為 true 則執行敘述區塊 1, 運算式的值若為 false, 則執行 敘述區塊 2, 其流程圖如 : ¹Bºâ true false ±Ô z Ï ô 1 ±Ô z Ï ô 2 2. 敘述區塊內可以放置任何合法敘述, 當然也可以再放置 if;if 有 if, 稱為巢狀 if, 請看範例 4-2c 3. 以 敘述可依 a 的大小評量其及格與否 if(a>=60)? " 及格 "; else? " 不及格 "; 4. C++ 為了強調語法的簡潔性, 若決策的結果, 只為求得簡單的運算式, 則可使用以 敘述的㆔元運算子 (? :), 其 運算式 2 與運算式 3 的括號只是增加程式的可讀性, 此兩括號的有無並不影響程式的執行結果, 當運算式 1 的值為 true 時, Z= 運算式 2, 當運算式 1 的值為 false 時, 則 Z= 運算式 3, 請看範例 4-2b Z = ( 運算式 1)? ( 運算式 2) : ( 運算式 3) ; 範例 4-2a 同 範例, 但當成績小於 60 時, 也要印出 不及格 4-6
決策敘述 4 題目分析 本例是典型的雙向分岐的決策, 此時可用 if else 實現程式的要求 執行結果 程式列印 //--------------------------------------------------- void fastcall Tfrm::btnstartClick(TObject *Sender) int a; lblout->caption="" ; a=strtoint(ediscore->text); if (a >=60) lblout->caption=" 及格 " ; else lblout->caption=" 不及格 "; //--------------------------------------------------- void fastcall Tfrm::btnendClick(TObject *Sender) Close(); //--------------------------------------------------- 4-7
程式說明 本例的 if 及 else 敘述區塊均只有㆒個敘述, 所以大括號可自行省略 範例 4-2b 請使用㆔元運算子, 重寫以 範例 輸出結果 程式列印 //----------------------------------------------------- void fastcall Tfrm::btnstartClick(TObject *Sender) int a; String strb; lblout->caption="" ; a=strtoint(ediscore->text); // 括號只是增加程式可讀性, 並不影響程式執行結果 strb=(a>=60)?(" 及格 "):(" 不及格 "); lblout->caption = strb; //----------------------------------------------------- 4-8
決策敘述 4 範例 4-2c 請寫㆒個程式, 完成以 要求 : 1. 輸入㆒個 0 100 的分數 2. 當分數大於 90 分時, 輸出 A 3. 當分數介於 80 89 時, 輸出 B 4. 當分數介於 70 79 時, 輸出 C 5. 當分數介於 0 69 時, 輸出 D 輸出結果 題目分析 1. 使用流程圖分析如 : 4-9
l Input a true a>=90? false true a>=80? false true a>=70? false strb="a" strb="b" strb="c" strb="d" Output strb µ² ô 4-10
決策敘述 4 2. 以 每㆒個決策點, 都有兩個分岐點, 所以適用 if else, 每㆒個 else 後 面均需再放置 if 做進㆒步決策 程式列印 //--------------------------------------------------------- void fastcall Tfrm::btnstartClick(TObject *Sender) int a; String strb; a=strtoint(ediscore->text); if (a >=90) strb="a"; else if (a>=80) strb="b"; else //else if 其實只是 else 後面放㆒個 if 敘述 if (a>=70) // 所以請不要當成另㆒敘述 strb="c"; else strb="d"; // 只有㆒個敘述, 可省略 lblout->caption=strb; //--------------------------------------------------------- void fastcall Tfrm::btnendClick(TObject *Sender) Close(); //--------------------------------------------------------- 4-11
4-3 switch...case ㆒個決策點若同時擁有㆔個或㆔個以 的解決方案, 此稱為多向分岐決策, 多向分岐決策雖也可使用 4-2c 的巢狀 if else 解決, 但卻增加程式的複雜度, 及降低程式可讀性, 若此㆒決策點能找到適當的運算式, 能使問題同時找到分岐點, 則可使用 switch case 敘述, switch case 語法如 : switch ( 運算式 ) case 常數 1: 敘述區塊 1; break; case 常數 2: 敘述區塊 2; break; case 常數 3:... [default: 敘述區塊 n;] 以 語法說明如 : 1. switch 的運算式值僅能整數或字元 2. case 的常數僅能整數或字元 3. 電腦將會依 switch 的運算式值逐㆒至常數 1 常數 2 尋找合乎條件的 case, 並執行相對應的敘述區塊, 直到遇到 break 敘述, 才能離開 switch 4. default 可放置特殊情況, 其兩旁加 括號表示此敘述可省略 ; 若省略 default, 且若沒有任何 case 滿足 switch 運算式, 則程式會默默離開 switch 敘述 5. 敘述區塊可放置任何合法的敘述, 當然也可放置 switch 或 if 4-12
決策敘述 4 範例 4-3a 試以 switch case 重作範例 4-2c 程式列印 //------------------------------------------------------- void fastcall Tfrm::btnstartClick(TObject *Sender) int a; String strb; a=strtoint(ediscore->text); if (a >100) strb=" 分數有誤 "; lblout->caption=strb; return; // 提早離開事件函式 switch (a/10) //a 的型別為 int, 所以 a/10 亦為 int case 10 : //100 90 均得到 A case 9 : strb="a"; break; // 提早離開 switch case 8: strb="b" ; break; case 7 : strb="c"; break; case 6: // 69~0 分均共用相同的處理方法 case 5: case 4: case 3: case 2: case 1: case 0: strb="d"; break; default: // 非以 條件, 均在 default 處理 strb=" 分數有誤 "; 4-13
lblout->caption=strb; //------------------------------------------------------- 程式說明 1. 有些語言可用逗號將兩種 case 放在㆒起, 但 BCB 每㆒ case 僅能放置㆒個常數, 所以若兩個或兩個以 case, 有相同的處理方法, 則應將兩個 case 分成兩個敘述 2. 使用 return 可提早離開事件函式 4-4 綜合範例 範例 4-4a 請設計㆒個程式, 可以解㆒元㆓次方程式 輸出結果 4-14
決策敘述 4 演算分析 1. 設有㆒元㆓次方程式如 : 2. 若 a=0 則應輸出 輸入錯誤 3. 令 4. 若 d = 0, 則方程式有唯㆒解, 否則若 d > 0, 則方程式有㆓解, 否則無實數解 表單配置 1. 使用 edia edib 及 edic 分別輸入方程式的㆔個係數 a b 及 c 2. 使用 lblout 輸出結果 程式列印 //------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "Unit1.h" #include <math.h> // 因欲使用 pow 次方函數 //------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" Tfrm *frm; //------------------------------------------------------- fastcall Tfrm::Tfrm(TComponent* Owner) : TForm(Owner) //------------------------------------------------------- 4-15
void fastcall Tfrm::btnstartClick(TObject *Sender) float a, b, c, d; String strb; a=strtofloat(edia->text); b=strtofloat(edib->text); c=strtofloat(edic->text); if (a==0) lblout->caption=" 輸入錯誤 "; return; d=pow(b, 2)-4*a*c; frm->caption=floattostr(d ); if (d==0) strb="only one answer, x1, x2= "+FloatToStr(-b/2*a); else if (d>0) strb="two answer, x1= " +FloatToStr((-b+sqrt(d))/2*a) +", x2= "+FloatToStr((-b-sqrt(d))/2*a); else strb="no real answer" ; lblout->caption=strb ; //------------------------------------------------------- void fastcall Tfrm::btnoutClick(TObject *Sender) Close(); //------------------------------------------------------- 程式說明 1. C++ 並無次方與根號運算子, 若欲使用次方或根號運算, 則應使用 pow 與 sgrt 等數學函式, 且應於標頭檔宣告引用數學函式如 : #include math.h 4-16
決策敘述 4 2. C++ 判斷是否相等的運算子為 ==, 請特別留意 範例 4-4b 請設計㆒個程式, 可以求解㆓元㆒次方程式的解 輸出結果 1. 圖左及右為單㆒解實例 2. 圖左為無限多組解, 圖右為無解實例 4-17
演算分析 1. 設㆓元㆒次方程式如 : 2. 令 ( 表示 ) 3. 假如則方程式無限多解, 且程式結束 4. 假如 d = 0, 則程式無解, 且程式結束 5. 6. 表單配置 4-18
決策敘述 4 程式列印 //------------------------------------------------------- void fastcall Tfrm::btnstartClick(TObject *Sender) float a1, b1, c1, a2, b2, c2, d; a1=strtofloat(edia1->text); b1=strtofloat(edib1->text); c1=strtofloat(edic1->text); a2=strtofloat(edia2->text); b2=strtofloat(edib2->text); c2=strtofloat(edic2->text); d=a1*b2-a2*b1; if ((a1*b2-a2*b1==0) && (b1*c2-b2*c1==0)) lblout->caption="too many answer"; return; if (d==0) lblout->caption="no answer"; return; lblout->caption="x= "+FloatToStr((c1*b2-c2*b1)/d ) +", y= "+FloatToStr((a1*c2-a2*c1)/d); //------------------------------------------------------- void fastcall Tfrm::btnoutClick(TObject *Sender) Close(); //------------------------------------------------------- 範例 4-4c 請輸入㆔角形㆔邊長, 首先判斷是否構成㆔角形, 其次判別㆔角形的 種類, 最後計算其面積 4-19
執行結果 演算分析 1. 輸入㆔角形㆔邊長 a b c 2. 將㆔邊長由小而大重新排列, 最小的放入 a, 其次放入 b, 最大的放入 c 3. 最小的兩邊之和若小於等於第㆔邊, 則此㆔邊未能構成㆔角形, 程式提 早離開 4. 假如 則為銳角㆔角形, 否則假如, 則為直 角㆔角形, 否則此㆔角形為鈍角㆔角形 5. 令 6. ㆔角形面積 = 4-20
決策敘述 4 表單配置 1. 表單配置如 圖 : 2. 分別以 edia edib 及 edic 輸入㆔角形㆔邊長 3. 以 btnstart 做為執行運算的依據 4. 以 lblstyle 輸出㆔角形的種類 5. 以 lblarea 輸出㆔角形的面積 程式列印 //--------------------------------------------------------- void fastcall Tfrm::btnstartClick(TObject *Sender) float a, b, c, d, t; float ab, cc; a=strtofloat(edia->text); b=strtofloat(edib->text); c=strtofloat(edic->text); 4-21
if (a > b) t=a;a=b; b=t; //a, b 交換 if (b > c) t=b; b=c; c=t; if (a > b) t=a; a=b; b=t; if (a+b <= c ) lblstyle->caption=" 無法構成㆔角形 "; lblarea->caption="" ; return; ab= pow(a, 2)+pow(b, 2); cc=pow(c, 2); if (ab > cc) lblstyle->caption=" 銳角㆔角形 "; else if (ab==cc) lblstyle->caption=" 直角㆔角形 " ; else lblstyle->caption=" 鈍角㆔角形 " ; d=(a+b+c)/2; lblarea->caption=floattostr(sqrt(d*(d-a)*(d-b)*(d-c))); //--------------------------------------------------------- void fastcall Tfrm::btnendClick(TObject *Sender) Close(); //--------------------------------------------------------- 4-22
決策敘述 4 程式說明 1. 設有 a, b, c ㆔數, 欲由小而大排列, 則其演算法如 : (1) a, b 比較, 若 a>b, 則兩者交換 (2) b, c 比較, 若 b>c, 則兩者交換, 此時 c ㆒定最大 (3) a, b 再比較, 若 a>b, 則兩者交換, 此時 a ㆒定最小 (4) 共比較㆔次, 即可由小而大排列 2. 假如有兩杯水 a, b 要交換, 則其交換演算法如 : (1) 先找㆒個空杯子 t (2) 將 a 的水暫時例入空杯子 t (t=a) (3) 將 b 的水倒入 a 杯子 (a=b) (4) 將 t 的水倒入 b 杯子 (b=t), 而完成兩杯水的交換 (5) 如果未找來空杯子 t, 而直接將 a 倒入 b, 則原來 b 杯子的水就不見了 範例 4-4d 閏年的判斷 執行結果 1. 如 圖左, 西元 100 年是平年 2. 如 圖右, 西元 400 年是閏年 4-23
演算分析 1. 西元的閏年為每 400 年必須有 97 次閏年, 其規劃方式如 : (1) 4 的倍數 依此條件共有 100 次 (2) 於 (1) 的條件, 扣掉 100 的倍數 依此條件, 共有 96 次 (3) 於 (2) 的條件, 再加回 400 的倍數 所以共有 97 次 2. 測試資料如 : ( 流程路線, 請對照 面的流程圖 ) 西元年份 性質 流程路線 3 平年 (1) 4 閏年 (2) 100 平年 (3) 200 平年 (3) 300 平年 (3) 400 閏年 (4) 600 平年 (3) 1200 閏年 (4) 2000 閏年 (4) 4-24
決策敘述 4 3. 以 演算分析, 流程圖分析如 : l é J è ~ a a4 = a % 4 ( ú¾l¼æ) a100 = a % 100 a400 = a % 400 false a4=0? true (1) strb=" ~" false a100=0? true (2) strb=" ~" false a400=0? true (3) strb=" ~" (4) strb=" ~" é X strb µ² ô 4-25
程式列印 //----------------------------------------------------- void fastcall TForm1::btnStartClick(TObject *Sender) int a, a4, a100, a400; String strb; a = StrToInt(ediYear->Text); a4 = a % 4; a100 = a % 100; a400 = a % 400; if (a4 == 0) if (a100 == 0) if (a400 == 0) strb = " 閏年 (4)"; else strb = " 平年 (3)"; else strb = " 閏年 (2)"; else strb = " 平年 (1)"; lblout->caption = strb; //----------------------------------------------------- 4-5 習題 1. 試寫㆒程式由使用者輸入㆒數值, 並由電腦判斷其為奇數或偶數 2. 假設所得稅稅率法則如 : 4-26
決策敘述 4 (1) 淨所得 30 萬以 6 % (2) 淨所得 30 80 萬之間 13 % ( 前面的 30 萬仍扣 6%, 超過 30 萬的 部分稅率為 13 %, 不是全部都扣 13%) (3) 淨所得 80 200 萬之間 21 % (4) 淨所得超過 200 萬 30 % 試寫㆒程式可以輸入淨所得, 並計算應繳稅額 例如淨所得若為 40 萬, 則其納稅金額計算如 : 300000 6 %+100000 13 %=21000 ( 超過 30 萬的部份稅率為 13 %, 不是全部 40 萬都是 13 %) 3. 寫㆒程式輸入 x 值, 並印出其所對應的值, 其函數對應如 : 4. 寫㆒程式輸入㆕數, 並由小而大輸出結果 ( 不可使用陣列 ) 5. 某㆒貨品定價 100 元, 若購買 500 件 ( 含 ) 以 打 7 折, 若購買 499 300 件則打 8 折, 若購買 299 100 件則打 9 折, 購買 100 件以 則不打折, 試寫㆒程式可以輸入購買件數而得總價 4-27
4-28