第五章 迴圈敘述 5-1 for 5-2 while與repeat 5-3 goto 5-4 with
人類的生活有許多事都是具有重複性的,例如一天有24小時、一星期有七天、同一門課要上18次才能拿到學分。程式設計的目的是要解決日常生活中可預期的事件,為了解決其重複性,Delphi的迴圈敘述如下: 1. for 2. while、repeat 3. goto 4. With for的使用時機為程式設計階段已知執行次數,請看5-1節。若未知執行次數,則應使用while或repeat,請看5-2節。goto則為非結構化語言的遺留產物,原則上它應已走入歷史,很多人建議應將goto敘述從結構化語言移除,但又擔心有些程式無法適應,所以目前goto敘述還是繼續存在,請看5-3節。with的功能為同時設定同一記錄的多個欄位、或是同一物件的多個屬性與方法,請看5-4節。
5-1 for 若於程式設計階段已知要執行的次數,則可使用for敘述,Delphi的for敘述語法如下: for變數 := 計數初值 <to/downto> 計數終值 do begin [敘述區塊1 ;] [break ;] [continue ;] [敘述區塊2 ;] end ; 以上語法說明如下: 1. for敘述的計數變數必須是序數變數,且又分為遞增計數與遞減計數。遞增計數時,採用to;遞減計數時,則使用downto。 2. 程式若執行到break,則會提早離開for迴圈。
3. 程式若執行到continue,則會略過continue下面的敘述區塊2,繼續執行下一個計數變量,請看範例5-1c。 for for begin begin 敘述區塊1; 敘述區塊1; break; continue; 敘述區塊2; 敘述區塊2; end; end; 4.以下程式片段可統計1至10的和。 sum:=0 for i:=1 to 10 do sum:=sum+i; 5.敘述區塊內可以放置任何合法的敘述,當然也可含有for。for內再含有for稱為巢狀迴圈,請看範例5-1e。
乘法 若沒有乘法運算子,則應如何計算乘法呢?答案是可用累加的方式來計算。例如62 x 38,亦就是62連續相加38次的結果,請看以下程式說明。
範例5-1a 請用for迴圈完成乘法運算。
〔自我練習〕 1.請寫一程式,可以輸出任一指定數字的九九乘法。
範例5-1b 試求2.1+1.9+1.7+…+(-7.1)之和。 程式說明: 1. Canvas是一個無圖示的物件,所以元件盤上並沒有Canvas元件的圖示,若要使用Canvas物件,直接在程式中鍵入物件名稱“Canvas”即可。Canvas的功能是輸出字串與繪圖,詳細說明請看第十三章的繪圖。 2. TextOut是輸出字串的程序,語法如下,其中x、y是顯示字串的座標位置。 Text (x,y,字串) 3. Delphi的計數變數只可以為序數型態,所以計數變數不可為小數。
範例5-1c 示範break及continue敘述。
質數的判斷 一個整數除了1及本身外,若無任何數可以整除它,則稱此數為質數。欲判別輸入的整數N是否為質數,最直接的方法就是將N連續使用2至N-1去除,若均無法整除,則N即為質數。像這種重複某一項工作,且有明確的起始值及終值的演算法,最適合使用for迴圈。
範例5-1d 示範質數的判斷。
巢狀迴圈 for的迴圈中又含有for的迴圈稱為巢狀迴圈,以下的程式片段可求10次1至20的和 procedure TForm1.btnStartClick(Sender: TObject); var n,i:integer; s:string; begin n:=StrToInt(Edit1.Text); s:= '是質數'; for i :=2 to n-1 do if (n mod i) =0 then s:='不是質數'; break; //exit 是離開 procedure end; Label1.Caption:=s;
〔自我練習〕 請寫一個程式,可以印出費式數列的指定項目(不可使用陣列)。 例如 : 輸入4,則輸出 1,1,2,3 輸入4,則輸出 1,1,2,3 輸入5,則輸出 1,1,2,3,5 輸入6,則輸出 1,1,2,3,5,8
範例5-1e 請使用迴圈輸出如下: 1. 本例共6列,所以外迴圈i為1至6。 * * * * * * * * * * * * * * * * * * * * * 程式說明: 1. 本例共6列,所以外迴圈i為1至6。 2. 內迴圈j處理星星的個數,與外迴圈i的關係 為j = i,所以內迴圈j為1至i。
自我練習 1.請寫一程式,輸出結果如下: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
自我練習 請寫一程式,輸出結果如下: 1 A 2 2 B B 3 3 3 C C C 4 4 4 4 D D D D 5 5 5 5 5 E E E E E 1 E E E E E 2 3 D D D D 4 5 6 C C C 7 8 9 10 B B 11 12 13 14 15 A
範例5-1f 試寫一程式,找出三位數的“阿姆斯壯數”。所謂阿姆斯壯數是指一數等於各位數的立方和,例如153=13+53+33。 程式說明: 本例使用三個迴圈i、j及k,i迴圈從1至9代表百位數、j迴圈從0到9代表十位數、k迴圈從0到9代表個位數,逐一檢驗100至999的三位數是否滿足阿姆斯壯數的條件。
〔自我練習〕 1.請寫一個程式,找出四位數中,滿足以下條件者。 abcd=a4+b4+c4+d4
5-2 while與repeat 上一節的for是用於已知迴圈次數,但有些情況我們於程式設計階段時並不知迴圈的執行次數,此時即可使用while或repeat敘述,其中while稱為前測試迴圈、repeat稱為後測試迴圈。而其差別在於,while是先測試條件運算式為真時,繼續執行迴圈,此種前測試迴圈有可能不執行迴圈內容便直接離開;repeat則是先執行迴圈,待條件運算式為真時再離開迴圈,也就是迴圈內容至少執行一次。
while 前測試迴圈的while語法如下: begin 敘述區塊1 ; break ; [敘述區塊2 ;] end ; 以上語法說明如下: while運算式 do begin 敘述區塊1 ; break ; [敘述區塊2 ;] end ; 以上語法說明如下: 1.運算式結果為真時,繼續執行迴圈敘述。 2. break敘述可提早離開迴圈。 3. 以下程式片段,可求1至10的和。 i:=1; sum:=0; while i<=10 do sum:=sum+i; i:=i+1;
repeat 後測試迴圈的repeat語法如下: while運算式 do repeat [敘述區塊1 ;] [break ;] [敘述區塊2 ;] write運算式 ; 以上語法說明如下: 1. 運算式結果為真時,離開迴圈。 2. break敘述可提早離開迴圈。 3. 以下程式片段,可求1至10的和。 i:=1; sum:=0; sum:=sum+i; i:=i+1; until i>=11;
除法 假如沒有除法運算子,該如何完成除法運算呢?可以將被除數連續減去除數、並計算可減去幾個除數,則可減去的除數個數即為商、剩下的被減數即為餘數,其演算法如下: 1. a =被除數。 2. b =除數。 3. 商數q = 0。 4. 所謂的商就是被除數a共可減去幾個除數b,也就是只要a大於等於b,就要執行以下敘述: a=a-b; q=q+1; 5. 本例以8除以3,實際演練如下: 1 a=8;b=3 a>=b成立,所以執行迴圈敘述 a=a-b=5 q=q+1=1 2 a=5;b=3 a=a-b=2 q=q+1=2 3 a=2;b=3 a>=b不成立,所以離開迴圈 q=2(商) a=2(餘數)
範例5-2a 示範以上除法運算。
進位數的轉換 一個十進位數a要轉為n進位數,其方法是將a連續除以n,直到整數商為0,其餘數的字串累加即為n進位數的值。 以上說明其演算法如下: 1.a為待轉換的十進位數。 2.n為某進位數。 3.r為餘數。 4.strn為n進位數的值。 5.將a連續除以n,直到整數商為0(也就是a>0,則要繼續除),其餘數的字串累加,即為n進位數的值。
6.本例以11轉為二進位,實際演練如下: (1) a=11;n=2;strn=' '; r=a%n=1; a=a/n=5; strn='1'; a>0成立,所以繼續迴圈。 (2) a=5;n=2;strn='1'; a=a/n=2; strn='11'(剛出爐餘數的1,要放在原strn的左邊) (3) a=2;n=2;strn=‘11’; r=a%n=0; a=a/n=1; strn='011'; (剛出爐餘數的0,要放在原strn的左邊) (4) a=1;n=2;strn='011'; a=a/n=0; (整數商已經為0;可離開迴圈) strn='1011'; (剛出爐的餘數1,要放在原strn的左邊) a>0不成立,所以離開迴圈。
以上演算法的原理解說如下: 1.若要將十進位的a轉為二進位,則以數學式表示如下: (a)10=a0+a121+a222+a323+a424--- =a0+2(a1+a221+a322+a423---)//a1以後,提出2 2.上式的a0為a除以2後所得的餘數,a1+a221+a322…則為a除以2而得的整數商,重複上式,直至整數商等於零為止 3.最先產生的餘數應放在2進位的最右邊 (a)10=(an…a3a2a1a0)2 以上演算法正適用前測試迴圈的while,請看以下範例說明
範例5-2b 請將10進位數轉為b進位數(本例暫討論b範圍為b<=9其餘,b>=11待陣列介紹後再論)。
輾轉相除法 輾轉相除法可以求兩數的最大公因數,其處理方式是將大數除以小數,若餘數為0,則小數即為最大公因數;若不為0,改以原小數為被除數、原餘數為除數,繼續相除,直到餘數為0,而促使餘數為0的除數,即為此兩數的最大公因數。演算法說明如下: 1. 輸入a、b兩數。 2. 假如b>a,則兩者交換。 3. r=餘數。 4. 將a除以b,得餘數r。假如,餘數不為0,則以原除數為被除數、原餘數為除數,重複執行a除以b,直到餘數為0,促使餘數為0的除數,即為最大公因數。 5. 本例以a=21,b=9,實際演練如下: (1) a=21;b=9; r=a%b=3; a=b=9; b=r=3; r=0不成立,所以繼續執行迴圈。 (2) a=9;b=3; r=a%b=0; a=b=3; b=r=0; r=0成立,所以離開迴圈,最大公因數為a=3。 以上演算法正適用repeat..until,請看以下範例說明。
範例5-2c 請寫一程式完成輾轉相除法,求兩數的最大公因數。
二分猜值法 求方程式的解時,若其解必在兩數之間(本例假設兩數為x1與x2),則可使用二分猜值法求解。其方法是先猜兩數的一半(本例假設為x)為方程式的解,將x代入原方程式,若使得原方程式值太大,表示解猜得太大,而正確解必在x1與x之間;反之,表示猜得太小,正確解必在x與x2之間。重複以上二分猜值法步驟,則每次均可將正確解的範圍縮小一半,等到x1與x2之間的距離非常小時(例如0.00001與0.00000001),則此時的x1或x2都可為該方程式的解。
二分猜值法的演算法如下: 1. 設求解的正數為x2,則其平方根必在x1=0與x2之間。 2. 首先猜x1+x2之和的一半x。 1. 根必在0與9之間。 2. 首先猜4.5,因4.5的平方大於9,表示猜得太大,所以縮小範圍為〔0,4.5〕。 3. 其次猜2.25,因2.25的平方小於9,表示猜得太小,所以縮小範圍為〔2.25,4.5〕。 4. 重複以上動作,直到猜值的範圍很小時,此範圍內的任意數即為解
範例5-2d 請寫一程式完成以上二分猜值法求任一正數的平方根。
5-3 goto 前面二節已介紹了結構化程式設計所需使用的迴圈敘述for 、while與repeat,原則上使用以上敘述再配合break及continue,即可解決程式設計所遇到的問題。goto是一種非結構化程式設計所遺留的產物,原則上是一個不該鼓勵使用的敘述,且目前的開發工具Java已將goto去除,所以強烈建議讀者不要刻意學習goto的用法,但還是擔心有人不習慣沒有goto的窘境,因此本節介紹goto用法。 使用goto之前必須宣告跳躍點的標記,其宣告語法如下,其中標記命名方式同識別字的命名。 Label 標記; 其次是標記的使用,其語法如下,跳躍點的標記可在goto的上面或下面,但不可跳離自己的程序、亦不可跳進別的迴圈。 goto標記; 標記 : //跳躍點的標記可在goto的上面或下面
範例5-3a 請以goto重作範例5-1a。
範例5-3b 請以goto重作範例5-2a。
範例5-3c 請以goto重作範例5-2c。
5-4 with 若我們要同時設定一個物件或記錄(記錄請看6-3節)的多個屬性或方法,可使用with敘述。例如以下程式片段可同時設定Form1物件的Color、Cursor、Width及Caption等屬性,其執行結果請自行開啟檔案e5-4ap。 with Form1 do begin Color:=clYellow; Cursor:=crCross; Width:=400; Caption:='with 示範 ' end;
習題 1.請用雙迴圈印出如下的執行結果: (1) 1 (2) 1 2 3 4 5 1 2 2 3 4 5 1 2 3 3 4 5 (1) 1 (2) 1 2 3 4 5 1 2 2 3 4 5 1 2 3 3 4 5 1 2 3 4 4 5 1 2 3 4 5 5 (3) 5 (4) E 4 4 D D D 3 3 3 C C C C C 2 2 2 2 B B B B B B B 1 1 1 1 1 A A A A A A A A A (5) * (6) * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2.請用雙迴圈印出如下的執行結果: (1) 11 21 31 41 51 61 71 81 91 101 12 22 32 42 52 62 72 82 92 13 23 33 43 53 63 73 83 14 24 34 44 54 64 74 15 25 35 45 55 65 16 26 36 46 56 17 27 37 47 18 28 38 19 29 20
請用雙迴圈印出如下的執行結果: (2) 11 12 22 13 23 33 14 24 34 44 15 25 35 45 55 16 26 36 46 56 66 17 27 37 47 57 67 77 18 28 38 48 58 68 78 88 19 29 39 49 59 69 79 89 99 20 30 40 50 60 70 80 90 100 110
請用雙迴圈印出如下的執行結果: (3) 101 92 102 83 93 103 74 84 94 104 65 75 85 95 105 56 66 76 86 96 106 47 57 67 77 87 97 107 38 48 58 68 78 88 98 108 29 39 49 59 69 79 89 99 109 20 30 40 50 60 70 80 90 100 110
請用雙迴圈印出如下的執行結果: (4) 11 21 31 41 51 61 71 81 91 101 22 32 42 52 62 72 82 92 102 33 43 53 63 73 83 93 103 44 54 64 74 84 94 104 55 65 75 85 95 105 66 76 86 96 106 77 87 97 107 88 98 108 99 109 110
4.寫程式求以下數列之和(n可任意輸入),此級數(數列之和稱為級數)是收斂或發散?(當n繼續增大 時,數列之和是否持續增大) 3. 寫程式計算下列結果: (1) s=7^2+10^2+13^2…+83^2。 (2) s=(1-1/2)(1-1/3)(1-1/4)+…(1-1/N) 。 (要先輸入N值) (3) s=1-1/2^2+1/3^2-1/4^2+…+(-1)^N/N^2。(要先輸入N值) 4.寫程式求以下數列之和(n可任意輸入),此級數(數列之和稱為級數)是收斂或發散?(當n繼續增大 時,數列之和是否持續增大)
6. ,請寫程式估算sinx之值,精確度達小數第五位。此級數是收斂或發散?(x要用弳度量)
9. 請寫一個程式,輸入一正整數,將其質因數分解後印出其式子,例如: 9. 請寫一個程式,輸入一正整數,將其質因數分解後印出其式子,例如: 輸入:319 輸出:319=11*19 輸入:19 輸出:19=質數 輸入:521752 輸出:521752=2^3*7^2*11^3 10. 請寫一程式,可以判斷其是否為質數。 11. 請找出小於等於100的所有質數。 12. 請寫一程式,可以累加所輸入的數字,設計階段並不知數字個數,直到輸入值是-1時,印出所輸入數字的最大值、最小值及平均。
13. 請寫一個程式,可以處理分數的加減乘除運算,運算之後的結果應約分化為最簡分數或整數。例如: 13. 請寫一個程式,可以處理分數的加減乘除運算,運算之後的結果應約分化為最簡分數或整數。例如: 14. 請寫一程式,可以協助使用者將任意小數轉為分數,例如, 0.3= = (可以約分時要約分) 15. 同第四章第7題,若該公司有五種產品,且每一顧客可能一次購買1至5種產品,請寫一程式,可以列出其購買明細及總金額。