《算法與程序設計》是《信息技術》(選修1)的內容,同學們通過該課程的學習,不僅掌握了許多編程技巧,而且用計算機分析問題和解決問題的能力也得到了提高。但我們在教學實踐中發現,對于許多初學者,迅速掌握循環結構并用于具體問題的解決,并不是一件容易的事情。下面我們結合一些具體實例,分析循環結構的特點及其編程方法。
一、 循環從FOR語句開始
循環結構可以減少程序重復書寫的工作量,用于描述重復執行某段算法的問題,這是程序設計中最能發揮計算機特長的程序結構。應用循環結構進行程序設計,關鍵是正確地構造出循環體,以及設置好循環變量的初值、循環的終止條件。FOR語句是一種最簡單、基礎的循環結構,它的初值、終值和步長顯式地體現在語句中。因此,我們可以從FOR語句出發,逐步探究其它循環結構的特點及用法,以期達到事半功倍的效果。
例1 求1+1/2+1/3+……+1/100的值。
Private Sub Command1_Click()
s = 0
For i = 1 To 100
s = s + 1 / i
Next i
Print \"s=\"; s
End Sub
這是一個簡單的循環程序,程序中包含了循環結構的一些基本概念,如循環變量、初值、終值、步長、循環體和累加和等,教學時可對其進行適當的變形、改造或擴充,如修改變量的初值,改累加為累乘,或在循環體中強行修改循環變量的值等,讓學生對這些基本概念有一個初步的了解。
例2 計算S=1+-+-……+-的值。
Private Sub Command1_Click()
s = 1
k = 1
For i = 1 To 100
s = s + 1 / (i * (i + 1)) * k
k = -k
Next i
Print \"s=\"; s
End Sub
這是上例的延伸和擴展,編程時要解決三個問題:①第一項與其它項有不同的規律,如何處理?②從第二項開始,每項的分母均由兩個相鄰的自然數相乘,如何表示?③如何實現運算符號的交替變換?若能引導同學們找出解決這些問題的方法,對循環結構的理解也就前進一大步了。
例3 輸入10個實數,輸出其中的最大數和最小數。
Private Sub Command1_Click()
x = InputBox(\"請輸入第1個數\")
Max = x
Min = x
For i = 2 To 10
x = InputBox(\"請輸入第2到第10個數\")
If x > Max Then Max = x
If x < Min Then Min = x
Next i
Print \"max=\"; Max, \"min=\"; Min
End Sub
在例1、例2中,循環變量的值直接參與了算式的運算。但在本例中,循環的作用只是用于統計輸入的個數,循環變量的不同作用有助于學生更好地理解循環結構。此外,我們在教學中引入了算法設計及預處理的概念,讓學生了解要想寫出一個好程序就必須先設計出一個好算法,就養成一個好的編程習慣。
二、 循環從DO語句深入
FOR循環可以解決許多重復執行的問題,但FOR循環一般用于解決初值和終值已知,且步長值為順序遞增或遞減的問題。對于滿足某種條件的重復執行問題,建議在熟練掌握FOR循環后,引入DO循環加予解決。
例4 已知=1++×+××+×××+……,當序列中某乘積項的值小于0.000000001時,表達式的值可作為的近似值,試計算的近似值。
Private Sub Command1_Click()
s = 0
k = 1
i = 1
Do While k >= 0.000000001
s = s + k
k = k * i / (2 * i + 1)
i = i + 1
Loop
s = 2 * s
Print \"pi=\"; s
End Sub
這道題看起來很復雜。其實,通過分析我們可以發現,序列中的每一項均是在前一項的基礎上再累乘上一個新的分數,因此我們可以用一個變量存放累加和,用另一個變量存放累乘積,從而構造出滿足要求的循環結構。因無法確定重復執行的次數,本題最好采用DO循環來實現。在應用DO循環時,要注意提醒學生設置好循環變量的初值,在循環體內要有能夠改變循環控制條件的語句,否則將陷入死循環。
例5 利用輾轉相除法求兩個正整數的最大公約數。
Private Sub Command1_Click()
m = InputBox(\"請輸入第1個數\")
n = InputBox(\"請輸入第2個數\")
If m < n Then t = m: m = n: n = t
r = m Mod n
Do While r <> 0
m = n
n = r
r = m Mod n
Loop
Print \"最大公約數為:\"; n
End Sub
在前面幾個例子中,循環變量一般是有規律地遞增或遞減,循環特征明顯,代碼相對簡單。本題應用了一個經典的算法輾轉相除法,求解的問題要經過提煉和設計才能運用循環結構。編程時應用了條件分支,輾轉相除以及變量替換等概念和方法,循環的終止條件是動態生成的,學生不易理解與掌握,教學時可先手工模擬再編程實現。
DO循環有四種不同的格式,區別在于循環終止條件的判別方式及執行順序上,只要熟練掌握了其中的一種格式,其它格式的應用也就水到渠成了。
三、 循環從多重嵌套中提升
多重嵌套的循環結構是一個比較難的知識點,也是容易使學生喪失信心的內容。教學時不要急于求成,可從最簡單的二重嵌套循環出發,先讓學生手工模擬程序的執行過程,了解循環變量的變化情況,再逐步深入解決實際問題。
例6 輸出一張“九九乘法表”。
程序一:
Private Sub Command1_Click()
For i = 1 To 9
For j = 1 To 9
Print Tab((j - 1) * 13); i; \"*\"; j; \"=\"; i * j;
Next j
Next i
End Sub
程序二:
Private Sub Command1_Click()
For i = 1 To 9
For j = 1 To i
Print Tab((j - 1) * 13); i; \"*\"; j; \"=\"; i * j;
Next j
Next i
End Sub
程序三:
Private Sub Command1_Click()
For i = 1 To 9
For j = 1 To i
Print Tab((j - 1) * 13); j; \"*\"; i; \"=\"; i * j;
Next j
Next i
End Sub
“九九乘法表”是一個不錯的二重循環入門例,“程序一”許多學生可以很快寫出。接著,可引導學生觀察“程序二”,了解如何通過改變循環變量的初值或終值來改變循環執行的次數,從而改變“九九乘法表”的形狀,最后再與“程序三”比較,找出它們之間的異同點,更好地理解多重嵌套循環的執行過程。
例7 輸出自然數1~100之間的所有素數。
Private Sub Command1_Click()
Print 2; \" \"
For i = 3 To 100
flag = True
For j = 2 To Int(Sqr(i))
If i Mod j = 0 Then
flag = False
Exit For
End If
Next j
If flag = True Then Print i; \" \"
Next i
End Sub
這道題運用了三種編程技巧:①將與其它素數性質不同的素數2單獨輸出,簡化編寫步驟;②設置了一個布爾類型的標志變量,用于判斷找到的數是否為素數;③利用exit for語句中止內層循環的執行,提高運行速度。編程時可讓學生先寫出判斷一個數是否為素數的程序段(內循環),然后在它的外面再嵌套另一重循環,輸出題目要求的其它素數。
例8 將2~100中的所有自然數分解為其質因子的乘積,輸出如下形式:
2=2
3=3
4=22
……
100=2255
Private Sub Command1_Click()
For i = 2 To 100
k = i
j = 2
First = True
Print k; \"=\";
Do While k > 1
Do While k Mod j = 0
If First = True Then
Print j;
First = False
Else
Print \"*\"; j;
End If
k = k j
Loop
j = j + 1
Loop
Next i
End Sub
這是一道比較難的多重循環嵌套練習題。其中,最外面的FOR循環用于提供所有待分解的自然數,中間的DO循環用于分解出每個數中不同的因子,最里面的DO循環用于分解出每個數中相同的因子,環環相扣,層層遞進,綜合應用了本文中介紹的多種編程技巧,同學們若能仔細揣摩認真分析,一定會有許多感觸和收獲。
總之,在教學中按照FOR、Do...Loop多重嵌套的順序授課較好。For語句中對于循環結構的基本要素都提煉出來了,后者需要挖掘隱含的語法要素;如后變量及初值,循環體中要有修改循環變量值的表達式使得循環結束。由于一開始的新課例子導入激發了學生的求知欲,渲染了良好的課堂氣氛,讓學生帶著問題聽課,有的放矢,從而提高了教學效果。