摘?要:數(shù)據(jù)結(jié)構(gòu)加算法等于程序,算法本身就難于理解,對(duì)于初學(xué)程序設(shè)計(jì)的學(xué)生,尤其在中學(xué)階段,學(xué)生的理解能力有限,如何在難于理解較為繁雜的算法學(xué)習(xí)中找到一種適合中學(xué)生理解的方式,是在中學(xué)開(kāi)展算法課程的關(guān)鍵。
關(guān)鍵詞:高精度;排序;遞推;遞歸;搜索回溯;貪心;分治算法;廣度優(yōu)先搜索算法;動(dòng)態(tài)規(guī)劃
算法有簡(jiǎn)單的,也有復(fù)雜的,我們學(xué)習(xí)任何一種新知識(shí),都應(yīng)該從簡(jiǎn)單的入手,算法在信息學(xué)奧賽這門課中,大致分為以下內(nèi)容:高精度算法、數(shù)據(jù)排序、遞推算法、遞歸算法、搜索與回溯算法、貪心算法、分治算法、廣度優(yōu)先搜索算法、動(dòng)態(tài)規(guī)劃。對(duì)于每一種類型的算法都應(yīng)該循序漸進(jìn),而不應(yīng)該一個(gè)內(nèi)容學(xué)到底,然后在進(jìn)入一個(gè)新的內(nèi)容,算法的學(xué)習(xí)對(duì)于中學(xué)生來(lái)說(shuō),利用業(yè)余時(shí)間學(xué)習(xí),需要數(shù)年的時(shí)間,學(xué)習(xí)算法前應(yīng)該對(duì)一門語(yǔ)言有所了解,例如應(yīng)該學(xué)習(xí)了數(shù)據(jù)類型、運(yùn)算符、表達(dá)式、順序結(jié)構(gòu)、分支結(jié)構(gòu)、循環(huán)、函數(shù)等。
學(xué)習(xí)一種類型的算法應(yīng)該設(shè)置不同的問(wèn)題,而這些問(wèn)題由淺入深,彼此間有聯(lián)系,最后在拋出一個(gè)綜合的問(wèn)題,抽絲剝繭,分析問(wèn)題,解決問(wèn)題,很多學(xué)生在學(xué)習(xí)完了一種方法之后發(fā)現(xiàn)一講就懂,做題就無(wú)從下手,我們應(yīng)該分析學(xué)生為何出現(xiàn)這種情況,算法本身就比較抽象,每個(gè)學(xué)生理解的能力都不同,具體問(wèn)題具體分析,我在平時(shí)授課之余,會(huì)在學(xué)生寫算法,調(diào)試程序的過(guò)程中進(jìn)行跟蹤,發(fā)現(xiàn)學(xué)生的問(wèn)題,才能找到學(xué)生哪里理解有問(wèn)題,哪里吸收不到位,然后進(jìn)行教學(xué)反思,重新設(shè)計(jì)課件,重新設(shè)計(jì)問(wèn)題及思路引導(dǎo),然后再重新講解,發(fā)現(xiàn)效果好了很多。算法描述一般會(huì)使用自然語(yǔ)言、流程圖、和偽代碼。在很多程序設(shè)計(jì)書籍中都推薦使用流程圖,但是我發(fā)現(xiàn)很多程序設(shè)計(jì)老師都是介紹下流程圖,最后講解復(fù)雜程序時(shí)都用的自然語(yǔ)言或偽代碼,我個(gè)人也偏向自然語(yǔ)言,算法就是解決生活中實(shí)際問(wèn)題的方法,我們?cè)谥v解算法時(shí)不應(yīng)該將任何問(wèn)題跟程序的代碼相關(guān)聯(lián),很多同學(xué)在看到問(wèn)題后,第一個(gè)閃現(xiàn)在腦中的畫面就是用循環(huán)、還是分支、還是函數(shù)、還是遞歸,而不是想生活中我們?nèi)绾稳ソ鉀Q這些問(wèn)題的,這就讓學(xué)生陷入一種先去想我學(xué)了哪些程序設(shè)計(jì)工具,看看哪個(gè)工具合適,而不是先想問(wèn)題求解方法,設(shè)計(jì)出方法,再考慮這些方法的可行性,可行性沒(méi)問(wèn)題,再考慮用程序設(shè)計(jì)如何解決。那這種問(wèn)題我們一定要對(duì)學(xué)生進(jìn)行糾正,養(yǎng)成良好的思考順序和習(xí)慣,才能在算法中走得更遠(yuǎn)。
下面我以在教學(xué)中的一些實(shí)例來(lái)進(jìn)行說(shuō)明闡述觀點(diǎn)。
一、?輸入一個(gè)數(shù),判斷其是否為回文數(shù)
其實(shí)這個(gè)問(wèn)題并不難,學(xué)生已經(jīng)學(xué)習(xí)了取余用“%”,也學(xué)習(xí)了取整用“/”,并且也練習(xí)了水仙花數(shù)的判斷,就是將某一個(gè)3位整數(shù)的百位數(shù)、十位數(shù)、個(gè)位數(shù)取出來(lái),然后判斷每位數(shù)的3次方的和是否跟原數(shù)相等。學(xué)習(xí)了以上知識(shí),會(huì)發(fā)現(xiàn)對(duì)于判斷是否為回文數(shù)已經(jīng)沒(méi)有新知識(shí)了,把這個(gè)問(wèn)題拋給學(xué)生,他們很難想出如何解決這個(gè)回文數(shù)問(wèn)題。我們從實(shí)際問(wèn)題出發(fā),什么樣的數(shù)為回文數(shù),正讀倒讀都一樣的整數(shù)為回文數(shù),每位同學(xué)都知道,那么如何判斷呢?如何取出一個(gè)整數(shù)的各個(gè)位數(shù),大家都會(huì),利用對(duì)10取余和取商操作即可將每位數(shù)拿出來(lái),這個(gè)在以前學(xué)過(guò)的水仙花數(shù)中都學(xué)習(xí)過(guò),那么取出來(lái)不是問(wèn)題,如何判斷呢?我們?nèi)绻阉寡b回去,判斷2個(gè)數(shù)的大小即可。那么看似問(wèn)題解決了,仔細(xì)觀察,不難發(fā)現(xiàn),我們是任意輸入一個(gè)整數(shù),沒(méi)有確定整數(shù)是幾位數(shù),前面學(xué)過(guò)的水仙花是固定的3位數(shù),那么唯一的問(wèn)題就是如何從一個(gè)不確定位數(shù)的整數(shù)中取出各個(gè)數(shù),這個(gè)是以前沒(méi)有講過(guò)的,也是沒(méi)有做過(guò)案例的,對(duì)于學(xué)生來(lái)說(shuō)這就是一個(gè)沒(méi)有學(xué)過(guò)的新知識(shí),新知識(shí)必須新授課,需要老師引導(dǎo)講解,不然幾乎不可能讓學(xué)生自己想出來(lái),有效的思考是必要的,無(wú)用的思考浪費(fèi)時(shí)間沒(méi)有任何意義,所以我重新設(shè)計(jì)了授課方式,先從另一個(gè)問(wèn)題入手,拋出另一個(gè)問(wèn)題,輸入一個(gè)整數(shù)n,輸出每位數(shù)的和,即輸入整數(shù)123,輸出6。那么這個(gè)問(wèn)題也是從一個(gè)不確定位數(shù)的整數(shù)中取數(shù),然后將其累加,取數(shù)依然還是用%和/來(lái)取,這個(gè)問(wèn)題相對(duì)簡(jiǎn)單,并且能將以前學(xué)過(guò)的水仙花和我們要解決的回文數(shù)聯(lián)系起來(lái),這個(gè)學(xué)生思考了幾分鐘之后,部分同學(xué)得出一個(gè)結(jié)論,先用整數(shù)n對(duì)10取余數(shù),累加到s中,然后個(gè)位數(shù)的數(shù)字就可以舍去,例如123%10=3;3累加后就不再需要了,我們把123變成12,即n=n/10,在對(duì)10取余數(shù),得到2,再次累加,如此反復(fù),那么做到什么時(shí)候截止呢?當(dāng)n>0時(shí)候做,當(dāng)n為個(gè)位數(shù)時(shí)在對(duì)10取商則為0,問(wèn)題解決。這個(gè)問(wèn)題解決了,那我們?cè)诨仡^看看回文數(shù),發(fā)現(xiàn)位數(shù)不確定的取數(shù)不是問(wèn)題了,貌似問(wèn)題解決,學(xué)生開(kāi)始寫算法,發(fā)現(xiàn)如何將取出來(lái)的數(shù)倒裝呢?例如12321,最后一位取出來(lái)放到m中,如何將最后一位變成第一位,需要乘以10000,位數(shù)不確定我們不知道乘多少,乘完后還需要累加,所以我們將m初始化為0,并且將輸入數(shù)n復(fù)制一份給num,每次我們都乘以10在累加,這樣隨著取數(shù)的過(guò)程,就可以累加出原數(shù)的倒裝數(shù),這個(gè)技巧也是以前沒(méi)有過(guò)的,即while(n>0){m=m×10+n%10;n=n/10},最后我們判斷num與m是否相等就可以判斷輸入數(shù)n是否為回文數(shù)。最后完成算法書寫,程序調(diào)試。經(jīng)典的算法是需要記憶的,這個(gè)記憶是打引號(hào)的,我們應(yīng)該記憶的是這些算法的特征,應(yīng)該記憶的是完成某個(gè)特定功能的編程技巧,而不是生硬的代碼,在編程學(xué)習(xí)的過(guò)程中,我就發(fā)現(xiàn)一些學(xué)生在講授過(guò)程中聽(tīng)課很認(rèn)真,也能跟老師很流暢的做交流,寫代碼的時(shí)候也很流暢,過(guò)幾天之后同樣的問(wèn)題,重新做的時(shí)候發(fā)現(xiàn)有些無(wú)從下手的感覺(jué),少部分同學(xué)仍然能夠?qū)懗鰜?lái),這就提示我們老師在教授學(xué)生的時(shí)候要注意總結(jié),要提醒學(xué)生哪些是需要理解的記憶,而不是背代碼,學(xué)生覺(jué)得自己并沒(méi)有背代碼,是因?yàn)閯傊v完,憑著印象在書寫,很容易完成,這道例題我在給學(xué)生總結(jié)時(shí)會(huì)提示學(xué)生我們需要記憶的是我們用取數(shù)倒裝累加的方式來(lái)進(jìn)行判斷,需要記憶的技巧是乘10累加,整數(shù)位會(huì)往左依次移動(dòng)。
二、?高精度算法
在高精度算法中,高精除法的算法模擬以高精除以單精為例的較多,高精除以單精中,還是利用取商符號(hào)/來(lái)進(jìn)行,在得出商c數(shù)組及下一個(gè)除數(shù)時(shí)利用的技巧在上一個(gè)實(shí)例是一致的,即c[i]=(x×10+a[i])/b;x=(x×10+a[i])%b;這種經(jīng)典的編程技巧我們需要記憶,需要熟練掌握,對(duì)于以后復(fù)雜的程序我們才會(huì)想起來(lái)如何處理。
三、?遞歸和回溯
遞歸算法中同學(xué)們最難以理解的是程序進(jìn)入到哪一層,遞歸的退出機(jī)制是什么?較為簡(jiǎn)單的遞歸實(shí)例我們通常以階乘入手,然后我們可以循序漸進(jìn)的接觸集合的全排列,經(jīng)典的例題還是漢諾塔游戲,這些例題同學(xué)們都比較容易理解,當(dāng)我們進(jìn)入到回溯算法時(shí),例如素?cái)?shù)環(huán)問(wèn)題,我發(fā)現(xiàn)同學(xué)們很難理解,他們難理解的原因除了回溯上一步以外,仔細(xì)研究發(fā)現(xiàn)他們難理解的還是遞歸的退出,由于回溯算法中一般都會(huì)嵌套遞歸,搜索回溯算法中大部分程序都是迭代中加遞歸,這對(duì)于遞歸的理解更上了一個(gè)層次,導(dǎo)致很多同學(xué)從一層遞歸中退出后不知道循環(huán)變量執(zhí)行到了哪里而產(chǎn)生困惑,我發(fā)現(xiàn)同學(xué)不能深入理解是因?yàn)椴恢肋f歸執(zhí)行到了哪一層,回溯的步驟以及循環(huán)變量執(zhí)行到具體的哪一個(gè),找到學(xué)生困惑的根源才能給學(xué)生解惑,所以我在實(shí)際教學(xué)中會(huì)取循環(huán)變量能完成問(wèn)題效果的情況下盡量小,通過(guò)畫圖的方式結(jié)合一步一步演示程序執(zhí)行的過(guò)程中變量值的變化,讓學(xué)生知道程序每一步是怎么運(yùn)行的,尤其遞歸的退出及回溯步驟中各個(gè)變量的變化情況,讓學(xué)生充分了解回溯的過(guò)程。學(xué)生理解了,程序自然寫起了就會(huì)非常流暢,學(xué)生才可能在實(shí)際的問(wèn)題中寫出回溯的步驟。
談到回溯自然避不開(kāi)高斯提出的經(jīng)典的八皇后問(wèn)題,這是一個(gè)典型的回溯問(wèn)題,我們?cè)诨厮輪?wèn)題中總結(jié)出了遞歸回溯的框架,有固定的2種格式,然而我們發(fā)現(xiàn)除了這些問(wèn)題以外,保存當(dāng)前狀態(tài)也是一個(gè)難點(diǎn),在這個(gè)問(wèn)題中,八皇后問(wèn)題關(guān)于行列斜線的皇后放置狀態(tài)我們用了3個(gè)數(shù)組來(lái)表示,這也是一個(gè)理解難點(diǎn),大名鼎鼎的約瑟夫問(wèn)題,是用1個(gè)1維數(shù)組來(lái)表示人出圈的狀態(tài),學(xué)習(xí)完之后再去學(xué)習(xí)八皇后會(huì)讓學(xué)生更容易理解,有些狀態(tài)我們可能會(huì)用到二維數(shù)組,這也是一個(gè)技巧,有些可能用的是布爾類型的數(shù)組,在八皇后問(wèn)題中我們用數(shù)組a來(lái)表示每一行的皇后,例如a位第一行的皇后,a[5]表示第5行的皇后,a[5]=3,表示第五行的皇后放置到了第3列,我們用b數(shù)組表示列是否放置了皇后,c數(shù)組和d數(shù)組來(lái)表示兩種方向的斜線皇后的狀態(tài)。這在后面中國(guó)象棋中跳馬的遍歷問(wèn)題中也會(huì)用到,這些技巧需要理解的記憶。
如何讓中學(xué)生輕松的學(xué)習(xí)算法這門課呢?找到學(xué)生難于理解的問(wèn)題根源,將復(fù)雜問(wèn)題通過(guò)有聯(lián)系的實(shí)例進(jìn)行講解訓(xùn)練,將復(fù)雜問(wèn)題用分治思想抽絲剝繭化為小問(wèn)題來(lái)逐一解決,這些方法運(yùn)用得當(dāng),我們驚喜地發(fā)現(xiàn),很多學(xué)生對(duì)于算法的理解與掌握都上了很大一個(gè)臺(tái)階。
參考文獻(xiàn):
[1]黃榮燕.淺析加強(qiáng)中學(xué)生議論文寫作思辨性的方法[J].高考,2019(3).
[2]陳輝斌.淺析初中生物教學(xué)中學(xué)生自主學(xué)習(xí)能力的培養(yǎng)[J].考試周刊,2019(35).
作者簡(jiǎn)介:王輝,新疆維吾爾自治區(qū)烏魯木齊市,新疆農(nóng)業(yè)大學(xué)附屬中學(xué)。