無人機程式設計:家長培養學霸都先讓孩子學習少兒程式設計!濟南少兒程式設計

1 學程式設計的好處:

1)程式設計,能讓孩子戒掉遊戲癮

2)程式設計是問題導向,有助於提高解決問題能力

無人機程式設計:家長培養學霸都先讓孩子學習少兒程式設計!濟南少兒程式設計

這兩個觀點我也贊同,但程式設計的好處不僅在於此。我在之前寫的一篇文章提到了這兩個觀點。

無人機程式設計:家長培養學霸都先讓孩子學習少兒程式設計!濟南少兒程式設計

程式設計對於孩子認識到粗心的危害確有幫助。前些天,波音737 max機型由於失事而被全球禁飛,而美國航空管理局似乎承認其軟體存在問題。所以程式的正確性至關重要,讓一個粗心的人去做程式設計師,著實不讓人放心。程式設計對於避免沉溺於遊戲也很有幫助,因為程式設計為孩子打開了另一個視野,人人都想成為創造者,而不是被動地接受。

無人機程式設計:家長培養學霸都先讓孩子學習少兒程式設計!濟南少兒程式設計

至於程式設計與數學的關係,可以看我們以前的文章。

無人機程式設計:家長培養學霸都先讓孩子學習少兒程式設計!濟南少兒程式設計

除了上面的幾點外,我還想加兩點。

一是程式設計有助於學習英語。

這也是昍最近學程式設計的一點體會。學好了英語,程式中的有些變數名一看就大致知道是什麼意思,另外,當程式編譯出錯時,也可以大概看明白錯誤資訊,做出針對性的修改。

二是學習程式設計有助於提升宏觀思維。程式的執行一步一步是微觀的,但最後達到的效果是宏觀的。因此在理解一個程式時,常常需要跳出微觀,從宏觀上去解讀。這在後面的例子會看到。

2 迴圈結構—少兒程式設計的第一個坎

有一種觀點認為現在的奧數學習套路化了,已承擔不了邏輯思維能力培養的重任,因此程式設計將責無旁貸接過這一重任。程式設計有助於培養邏輯思維能力毋庸置疑,沒有嚴謹的邏輯思維,必然寫不好程式。

程式流程有三種結構:

順序結構、分支結構和迴圈結構

。前兩種都比較好理解,所謂順序結構就是一條道走到黑,沿著這條路一直走就可以到達終點;而分支結構則有岔路口,這時需要選擇走哪一條路,不同的人可能會選擇不同的路。這兩種結構孩子都比較好理解,在學習程式設計中,孩子遇到的第一個坎應該就是迴圈結構。可以這麼說,對少兒來說,熟練使用了迴圈,程式設計就學會了一半。

所謂迴圈,就是一段程式要反覆執行好多遍,甚至是一直執行下去。

在C++和大部分程式設計語言中,都提供了三種迴圈語句:for迴圈,while迴圈和do-while迴圈。

不論是哪種迴圈,迴圈都有三個要素:

1)迴圈變數

2)迴圈控制條件

3)迴圈體

無人機程式設計:家長培養學霸都先讓孩子學習少兒程式設計!濟南少兒程式設計

迴圈變數是迴圈控制條件中的主要輸入,用於改變迴圈執行的邏輯。這裡,會出現程式設計人員常犯的兩個錯誤:(1)迴圈變數沒有初始化或錯誤地初始化;(2)沒有改變迴圈變數的值,導致死迴圈。

迴圈控制條件用於控制迴圈的結束,這是迴圈邏輯的重點,其中的表示式可以是簡單的關係表示式,還可以是複雜的邏輯表示式。這裡,又會出現常犯的的一些錯誤:(1)迴圈條件表示式邏輯出錯,比如邏輯與和邏輯或用錯;(2)邊界條件判斷出錯。後一個錯誤很多時候是由於基本所有程式設計語言中陣列的第一個元素下標都是從0開始,因此遍歷所有元素的結束條件是”<”還是”<=”對許多初學者來說都會成為問題。

除了程式設計犯錯,用迴圈程式設計將涉及到另一個重要的問題,就是程式的效能。同樣是一段程式碼,迴圈執行的次數多少極大地影響了程式的執行時間。同一個問題,有可能一個程式需要1秒鐘就能得到執行結果,而另一個程式需要超過100秒才能得到執行結果。

迴圈體是程式執行的主要部分,在這裡面比較重要的是進行迭代和改變迴圈變數。迭代是程式設計和數學的一大區別,比如sum= sum +i; 在數學上,這個式子只有當i=0時才成立。但在程式設計中,由於=是賦值號,意思是把sum+i的結果賦值給sum,也就是sum獲得了一個新值。在C++和大部分程式設計語言中,與數學上判斷兩個數是否相等等同的運算子是==。這是包括一些有經驗的程式設計老鳥在程式設計時也會犯的一個錯誤,特別是在使用分支語句時,比如: if(i=5)cout i; 那麼不管i是否是5,都會輸出i,因為i=5是個賦值表示式而不是關係表示式。

無人機程式設計:家長培養學霸都先讓孩子學習少兒程式設計!濟南少兒程式設計

3 幾個例子

例1:判斷一個數是否為質數

根據質數的定義,如果一個數只能被1和它自身整除,那麼這個數就是質數。按照這個定義,可以很快地寫出程式,就是用2到n-1的數一個個地去除以這個數,如果都除不盡,那麼就是質數。

int i, n

cin>>n;

for(i=2; i<=“” p=“”>

if(n%i==0){

cout<<”不是質數”;

break;

}

if(i==n)

cout<<“是質數”;

這個程式裡,有個break, 表示跳出當前迴圈。也就是隻要有一個數除得盡n,那麼就不用再除了,否則會輸出多次“是質數“。迴圈結束時,如果i==n,也就是說2,3, …,n-1都除不盡n,則n是質數。這個簡單的程式,初學者也可能會犯一些錯誤:

易犯錯誤1:

迴圈初始化,i必須從2開始,而不是1,否則肯定不是質數;

易犯錯誤2:

迴圈控制條件表示式,應該是i<=n,否則也肯定不是質數;< p=“”>

易犯錯誤3:

if(i==n)而不是if(i=n)

當然,這個程式還有一個小問題,也就是邊界問題:如果輸入1,那麼由於迴圈並不執行,所以什麼都不輸出。為此,可以在前面加一句 if(n==1)cout<<“不是質數”。有了迴圈後,程式設計就需要多考慮一些極端的邊界條件,這是一個好的程式設計師的基本素養之一。

當然,這個迴圈可以改成如下的while迴圈:

cin>>n;

if(n==1)

cout<<”不是質數”;

i = 2;

while(i

i++;

if(i==n)

cout<<”是質數“

else

cout<<“不是質數”

學會分析迴圈結束條件和迴圈結束時變數的狀態非常重要。這就涉及到迴圈控制條件表示式的邏輯分析,也是一種宏觀思維,我們無需關係迴圈具體執行了多少次,只需要關注其最終結束時的狀態就行。這裡的while用了&&這個邏輯表示式,退出條件要麼是i>=n, 要麼是n%i==0。後者退出時i< p=“”>

需要說明的是,退出迴圈還有一種可能,就是迴圈體中使用了break語句,例如上面的for迴圈中所使用的那樣。

當然,如果到這就結束了,那就成純粹的程式設計語法練習了。程式不僅要正確,還要執行得更快才好。上面的例子中,如果輸入的數n是10001,那麼假如n是一個質數,迴圈體要執行9999次。怎麼才能減少執行除法的次數呢?

第一個想到的方法是:如果試到n的一半還除不盡,那就不用再試了。也就是把for迴圈改為:for(i=2;i<=n/2;i++)。這樣,就把除法的次數減少了一半。

再進一步,因為所有的質數只有一個偶數,其餘都是奇數。如果輸入的是個奇數,那麼就不用去試偶數了。於是,程式變為:

if(n==1)

cout<<“不是質數“

else if(n==2)

cout<<“是質數”

else

for(i=3; i<=n/2;i+=2)

也就是如果n為奇數,則從3開始到n/2, 每次增加2,即用奇數去除n。這樣做的除法次數就減為原來的1/4。

當然,這還不是最少的。如果一個數n不是質數,那麼一定可以表示為兩個數a和b的乘積,不妨假設n=a×b, 其中a<=b。因此a小於等於n的平方根,即a<=sqrt(n)。也就是說,從2開始試到不超過n的平方根的整數,如果還沒有一個除得盡n,那n就一定是質數。從而,程式變為:

for(i=2; i<=sqrt(n); i++)

再結合只有一個偶質數的事實,進一步可以變成:

if(n==1)

cout<<“不是質數“

else if(n==2)

cout<<“是質數”

else for(i=3; i<=sqrt(n); i+=2)

這樣,嘗試的次數只有n的平方根的一半了。對於輸入n=10001來說,最多隻需要嘗試不到50次就可以判斷出n是不是質數,相比於原來的9999次大為減少。

上面這個程式是判斷某一個數是否為質數。如果輸入n,要輸出所有不超過n的質數,那麼可以利用剛才的程式功能作為一個基本功能(一點點重用的思想),也就是對從2到n的每個數,都用上面的辦法去判斷其是否為質數。這實際上就引出了雙重迴圈的概念:

cin>>n;

for(i=2;i<=n; i++)

{

j= 2;

while(j<=sqrt(i)&& i%j!=0)

j++;

if(j>sqrt(i))

cout<

}

當然,對於這一問題本身還有更好的方法,就是用篩法求不超過n的所有素數,有興趣的可以參考我之前的文章《孤獨而高冷的素數》。

雙重迴圈對孩子來說是一個巨大的挑戰,因為第二個迴圈變數的取值通常受制於第一個迴圈變數的取值,因此分析清楚兩者的關係至關重要。這需要一點抽象思維,更要搞明白第一重迴圈和第二重迴圈各自的目的。在上面的例子中,第一重迴圈遍歷2到n中的每個數,判斷其是否為質數;第二重迴圈則是判斷某個數i是否為質數的具體做法,即按照素數的最佳化定義,遍歷不超過sqrt(i)的所有數j,看是否除得盡i。

無人機程式設計:家長培養學霸都先讓孩子學習少兒程式設計!濟南少兒程式設計

例2:在螢幕上輸出如下的三角形。

*

* * *

* * * * *

* * ** * * *

這就需要雙重迴圈,第一重控制輸出幾行,第二重控制每一行怎麼輸出。為了寫出這個程式,首先得搞清楚數量關係(實際上是一種樸素的函式概念):第i行需要輸出多少個*?

孩子需要分析出這裡的數量關係,即第i行輸出的‘*’的數量是2×i-1個。在輸出*之前,還要分析輸出的空格數量與行數i的關係。

例3:試說出下面程式的功能

cin >> n;

while(n>0){

cout<

n=n/10;

}

透過試著輸入幾個數並模擬迴圈執行,孩子可以看出這個程式的功能是把一個輸入的大於0的數倒過來輸出一遍。即如果輸入是123,那麼輸出是321。

正好最近昍在學進位制,因此順便給他普及一下進位制和移位的關係。學過程式設計的人都知道在二進位制裡,乘2可以用左移1位來實現,除2可以用右移1位來實現。而如果存在一個計算機採用的是十進位制,那麼n/10就是把n右移1位,n*10則是把n左移1位。所以,即便是不模擬程式的輸出,從宏觀的角度,也可以看出程式的功能。

當然,這個程式也可以改用for迴圈;

cin>>n;

for( ; n>0 ; n/=10)

cout<

再對比書上的下一個程式:

cin>>n;

while(n>0){

cout<

n=n/2;

}

這個程式的功能,從數學的角度,就是將10進位制數n不斷除2取餘,比如6,那麼輸出是011,也就是十進位制對應的二進位制數倒過來寫。但是,如果拋開我們人類的十進位制背景,在計算機裡n就是2進位制數,這個程式和上面的程式本質上是一樣的,就是每次把末位數輸出,然後右移一位,實現了把二進位制倒過來寫的功能。

最後說說幾種迴圈的用法。for和while都是先判斷迴圈控制條件是否成立再決定是否執行迴圈體,迴圈體可能一次都不執行。而do-while迴圈則不管三七二十一都會先執行一次迴圈體,再判斷是否要繼續執行迴圈,因此do-while迴圈至少執行一次迴圈體。

理論上,這三種迴圈可以互相轉化,用哪個主要看個人喜好。對我自己而言,如果迴圈執行的數量確定,那更願意用for迴圈,而如果迴圈的數量本身不定,則更願意用while迴圈。

無人機程式設計:家長培養學霸都先讓孩子學習少兒程式設計!濟南少兒程式設計