金凡 陳凱
記事本里的大兔子和小兔子
假設(shè)有一對小兔子,它們用一個月時間長大變成大兔子,然后再過一個月,生下一對小兔子,生下的一對小兔子也用一個月時間長大,再過一個月后又生下一對小兔子,并且假設(shè)之后每對大兔子每個月都要生一對小兔子,那么——這里并不是問幾個月后總共有幾對兔子,那其實就是求斐波那契數(shù)列了,這里的問題是,如果生下的每對小兔子都在大兔子的右側(cè)成長并且絕不隨便和大兔子交換位置——經(jīng)過特定時間后,大兔子和小兔子的序列會是怎樣的?順便說一下,假設(shè)有誰特別糾結(jié)于兔子近親繁殖的倫理問題,也可以把問題情境中的兔子改成能夠單姓繁殖的大理石紋螯蝦。
這個問題在紙上就能演算出來,假設(shè)一對小兔子用符號a表示,一對大兔子用符號b表示(把現(xiàn)實中的事物用符號來表示,是為了其后計算上的方便,如何合理設(shè)定符號,其實和計算思維技能有關(guān)),一開始的時候,人們看到的就是a,一個月后a變成了b,再一個月后,b生下a,因為a總是在b的右側(cè)成長,所以人們看到的就是ba,再下一個月,因為a變成b,b變成ba,所以人們看到的就是bab,以此類推,再往后一個月,看到的就是babba,再往后是bababbab??梢园l(fā)現(xiàn),從第二個月開始,序列的開頭是不變化的,而尾巴在不斷地變長:
a
b
ba
bab
babba
babbabab
在記事本中,可以通過不停地進行三步“全部替換”功能來自動生成序列:先把a全部替換成t,再把b全部替換成ba,最后把t全部替換成a就可以了。不用動太多腦筋,反復(fù)做這三步“全部替換”就能使得符號序列越來越長。這就體現(xiàn)出用迭代來實現(xiàn)自動化奧妙了。
畫圖軟件里的兔子序列
類似的迭代思想可以用到其他地方,例如,可以用畫圖軟件來生成兔子序列,方法很有趣。
首先,畫一個深色的框,如圖1。
然后,隨便畫條豎線,把框一分為二(分的位置不用太在意),在右側(cè)部分填上比較淺的顏色,如圖2。
接著,在深色框內(nèi)再畫豎線,這條豎線要比剛才的稍微長一些,然后同樣在右側(cè)部分填上比較淺的顏色,如圖3。
再接著,把當(dāng)前第二短的豎線的右側(cè)框的顏色變成深色,如圖4。
這個工作可以繼續(xù)下去,注意分割的豎線越來越長,每一次新分割出來的框,都將右側(cè)填上淺色,然后不要忘記,將當(dāng)前第二長的豎線的右側(cè)框填上深色,反復(fù)進行,很快就能得到兔子序列了,如上頁圖5。設(shè)深色為b,淺色為a,從左往右讀,就是兔子序列。
電子表格中的兔子序列
在電子表格中,可以有很多種方法來生成兔子序列,這里仍然借用在畫圖軟件中所使用的方法,將迭代過程變得更自動一些。
第一步:在第一行第一列的單元格中寫入b,然后在右側(cè)單元格中寫入公式“=b”,用拖曳功能,在第一行填充若干b,如圖6。
第二步:在中間某處相鄰的兩個單元格中連續(xù)填入1和a,于是右側(cè)部分就自動全部變成a,如圖7。
第三步:在鋪滿b的序列中間相鄰兩個單元格中填入2和a,于是2的右側(cè)部分變成a,如圖8。
第四步:找到比當(dāng)前序列中最大的數(shù)字小1的數(shù)字,在這里正是2減1得到1,在這個數(shù)字右側(cè)鋪滿a的序列最左側(cè)單元格中填入b,于是跟隨其后的符號都變成了b,如圖9。
第五步:從第三步開始重復(fù)此過程,但填寫的數(shù)字要逐漸變大。于是就逐漸生成兔子序列了。注意在讀數(shù)據(jù)的時候,連續(xù)的符號要當(dāng)成一個符號來讀。這個過程做熟練以后,可以用相當(dāng)快的速度生成兔子序列。
在Scratch里用兔子序列來畫樹
如果將小兔子a看成細樹枝,大兔子b看成粗樹枝,那么就可以應(yīng)用兔子序列模擬一棵樹的自動生長過程了(如上頁圖10)。
首先,在Scratch中添加tree鏈表,用來存放兔子序列。最初該鏈表中只有1項,存放著字符a,也就是樹的第一層。然后,制作“生長樹”“替換”和“分叉”三個模塊(如上頁圖11)。當(dāng)主程序運行一次“生長樹”時,將三次執(zhí)行“替換”模塊,完成前面所提到的三步“全部替換”。最后,利用“分叉”模塊將tree鏈表中所有值為“ba”的項分解為兩項。反復(fù)運行“生長樹”便可生成更長的兔子序列。例如,運行四次“生長樹”后,tree鏈表就增加到5項,它們分別為babba。
接著,添加一個小圓點角色并制作一個“畫樹枝”的模塊,讓小圓點以x1、y1為起始位置畫線段(如上頁圖12)。該模塊將會遍歷當(dāng)前的tree鏈表,遇到a,則畫長度為len的垂直線段,遇到b,則分叉畫兩條斜線段。畫好線段后,將小圓點當(dāng)前的位置分別存入x、y鏈表,它們將成為下一輪畫樹枝的初始位置。
再接著,制作“初始化”的積木,將程序中涉及到的鏈表設(shè)置為初始值,并設(shè)置畫筆大小和顏色,清空舞臺上所有畫線。最后,編寫主程序,根據(jù)用戶輸入的高度h來畫樹(如上頁圖13)。在畫完第一層之后,后續(xù)的h-1層就是一個重復(fù)迭代的“畫樹枝”過程。其中每一層樹枝的長度和樹的高度h以及當(dāng)前層數(shù)i存在一定關(guān)系,這個關(guān)系式可以自己進行調(diào)整。每畫完一層,就會再運行“生長樹”模塊,使樹的鏈表即兔子序列再變長,也就意味著樹又長高了一層。
當(dāng)然還可以繼續(xù)優(yōu)化程序,讓線段變得有粗細之分,并使角度發(fā)生隨機變化(如圖14),甚至可以讓每個節(jié)點是否繼續(xù)生長也有隨機變化的可能,讓某些節(jié)點長出樹葉、花果。通過不斷地優(yōu)化程序,可以使得這個程序所畫的樹更像大自然的樹。
為了給大家更多思考和想象的空間,本文沒有列出所有代碼,需要教師自己研究補充完整。因為代碼量比較大,在實際上課時,教師可將講課重點放在實現(xiàn)迭代過程的實現(xiàn)思路上,部分代碼可以直接提供給學(xué)生,如怎么分解符號串、以何種形式畫樹枝等,不必過多糾纏于代碼的實現(xiàn)細節(jié)。
面對同樣的兔子序列,可以使用各種軟件玩出很多花樣,哪怕只是簡單的記事本或畫圖軟件。因為計算思維是一種建立在計算機科學(xué)概念基礎(chǔ)上的思維方式,它并不局限于某類或某種軟件,甚至它也不局限于計算機,關(guān)鍵在于我們思維的方式:能否分解問題,通過抽象化、符號化,運用迭代、遞歸等方法將其轉(zhuǎn)化成為可以解決的問題。其實,在工作、生活和學(xué)習(xí)中,許多地方都隱含著用計算思維解決問題的策略,等待著大家去探索挖掘。