摘要:從計算科學的角度出發,對程序設計課程的教學方法進行探索與思考,介紹東南大學計算機科學與工程學院在改進教學理念及教學方法方面所做的嘗試。文章對教學理念的現狀及發展進行了分析,提出在教學中引入以數據意識和算法可行性為切入點的教學方法,運用推動思維、注重風格的教學理念來提高教學效率,從而促進教學質量的提高。
關鍵詞:程序設計;基礎教學;教學理念;形象思維;抽象思維
在計算機應用教學領域,程序設計課程是普遍開設的公共課程,歷經數十年的發展,人們認識到,學習程序設計已不只是學習一種軟件開發工具,更有意義的是學習和掌握一種適用于面向計算機及其計算環境的新型思維方法、特殊的邏輯表達和具有計算機應用特點的哲學理念。在最新的教育部高等學校計算機科學與技術教學指導委員會發布的《程序設計基礎課程教學實施方案》中提出,“在課程涉及的能力培養目標上,從提出問題、設計算法、選定數據表示方式,到編寫代碼、測試和調試程序,以及分析結果的整個程序設計過程中,培養學生抽象問題、設計與選擇解決方案的能力,以及用程序設計語言實現方案并進行測試和評價的能力[1]”。其中的能力培養目標是教學的核心目標,而在這門學科中,能力的培養實質上是一種腦力的培養。
對于初次學習計算機程序設計的學生來說,很多概念和術語都是陌生的,有些甚至感覺不易理解。在學習過程中,從外在的形象到內部的抽象,都需要逐步理解,學生的學習效率在很大程度上取決于是否感受到或掌握了計算科學的思維方法和理念。因此,在學生和教師這兩方面,都需要一些從計算科學的角度出發的觀察與思考。在課堂上,教學過程的主體是對學生講授知識,而在知識的表達上貫穿著老師自己的教學理念和基本思想的發揮。因此,樹立什么樣的教學理念是一個很值得思考的問題。
1引導學生重新認識數據
數據是程序工作的對象,開始學習時,學生都能理解可計算的數和文字、圖表等數據,然而很多情況下數據不是單一出現的,一個問題中涉及的數據是否存在內在關系,這種關系如何用程序設計語言描述或表達,往往是初學者忽視的。我們在教學中較早地引入數據觀點,對提高程序設計能力有著較好的基礎作用。所謂數據觀點,主要指數據的定義、數據關系、數據類型、數據存儲、數據訪問、訪問異常等一些在程序中與數據相關的問題,對這些問題應有明確的認識,了解解決這些問題的方法。
數據是程序運行時的核心。對問題進行分析后建立數據模型,是應用程序設計的主要基礎工作,特別是在面向對象程序設計的過程中,自定義數據類型成為主導,教學中應更加注重提高學生的數據抽象能力,學會數據模型的構造方法。由于數據所面對的是操作(方法),數據模型的結構關系到操作代碼和程序流程的質量,對程序的執行效率也有較大影響,在教學中可以通過實例做一些分析對比,使學生對此問題有足夠的認識。
數據是信息的載體,在信息處理系統中,計算和信息組成了一個不可分割的概念對[2]。在程序設計教學中,需要講解的另一個問題是如何利用數據來承載信息或表達信息。例如,程序狀態信息和程序環境的數據化表示方法以及這種表示對算法實現的作用和影響。在教學中使用的一個較為簡單的例子是說,二進制數運用自然界中具有二元狀態的物體來表示,與之相反,我們可以設定一些數來表示事物的不同狀態,或者說是把某種狀態或狀態符號稱為數據。例如,在冒泡排序程序中,使用一個取值為0或1的狀態變量標記在本趟掃描中是否發生了交換,以便提前結束循環從而節省程序運行時間。在算法的程序實現中較常用的非原始數據有些是邏輯數據,而何時需要使用邏輯數據,怎樣使用等都是學生面臨的新問題。數據與信息的關系、數據的合理組織是程序設計中的基礎技術,也是提高程序質量的重要技術,需要使學生認識到這一點。
直觀地看,能夠輸入計算機的信息都是數據。而實際上,要想在程序運行時把數據輸入計算機,需要做不少的準備工作,如數據的存儲方式、數據的類型聲明、數據的合法性檢驗、輸入/輸出界面的設計等。數據還是對算法和程序進行正確性檢驗所必需的依賴對象。學生如果能夠對數據問題有更多的理解和思考,則會在學習效率上有事半功倍的效果。
2從算法可行性的角度認識計算機
無論計算機的用途有何千差萬別,本質上它都是一種操作、處理符號的物理系統。對于計算機程序而言,計算就是對符號的操作,無論抽象度多么高的算法都要轉變為對應的程序代碼,最終都要被轉換為可執行的機器代碼。因此,算法的可行性總是老師對初學程序設計的學生所強調的要點。而要理解可行性,學生首先需要理解計算機的內部工作原理。
在計算機內的世界,將機器的行為和方法與現實世界中人的行為和方法相比較,既存在著一種固有的映射關系,更具有一些超越人的能力和表現。人們通常對計算機的描述是計算機以CPU為核心,這一點是確定的。雖然CPU是計算機的心臟,程序是在CPU中執行的,但馮?諾依曼體系結構的工作原理卻是以內存為中心,或者說從數據的角度看,內存中的數據是穩定狀態,數據在CPU中只停留瞬間,這一瞬間用來改變或轉移數據。再從算法的角度看,算法的流程控制依賴變量,而變量代表了某一存儲單元,程序流程的執行就是各個變量的內容和狀態的變遷序列。對于初學者而言,算法是否具有可行性,主要看它的計算方法是否能轉換為可用變量表達的表達式,或者是可由變量控制的基本工作流程。
例如,C/C++語言程序中的函數調用機制以及遞歸程序都是由基于內存中的棧區來實現的,學生只有理解了棧的機制和運用方法才能較快地理解遞歸算法和程序。按理說,用高級語言編程就是為了屏蔽底層的硬件,但是對于初學者來說,計算機的硬件工作環境應該了解清楚,甚至需要感覺擁有一種“內視力”,似乎看到程序的工作過程。可以說要做到心中有一個計算機。
數據結構的定義也需考慮內存的特點和局限來設計,即數據存儲表示的可行性。例如,學生對鏈表概念感覺很抽象,其問題實質在于如何抽象地描述數據的非連續存儲的物理實現。鏈表概念可以分為2層邏輯結構,一層是結點結構,另一層是鏈結構(主要成員是頭指針)。單是結點結構就要表述為把一個基本類型的變量(如整型變量a)和一個指針p整合在一起定義為結構變量Node,那么指針p就像變量a伸出的一個鉤子,這個鉤子可以用來拉住另一個結點(其實質是存儲了后繼結點的地址)。多個結點一個連一個地鉤住就形成了一條鏈,我們就稱p為鏈指針。而如果要使它能夠鉤住另一個結點,就必須規定該指針的類型,使它具有與自己所在結點相同的類型,從而使程序在編譯和執行時能夠限定它只能指向與本結點具有相同類型的其他結點。但在定義鏈指針類型時,定義本結點的描述還未結束,為什么又能使用這個未完成的類型名?可以解釋為由于指針的值只能存儲地址,編譯系統為指針類型規定了占用4個字節的空間長度,因此可以先對其進行聲明,等指針被使用時,前面的結點結構定義已經完成并生效,這是編譯系統為實現鏈表而特別采取的措施。對于鏈結構,需要強調表中的結點是動態生成的,沒有變量名,要想訪問一個結點只能先找到其前驅結點,從中取出它后繼結點的地址。由于第一個結點沒有前驅結點,因此必須安排一個表頭指針來存儲頭結點地址。在課堂上,隨時在黑板上畫出相應的示意圖,可以使學生更加直觀地理解所學習的概念。
可行性的考量基礎在于計算機工作原理對抽象高度的限制。例如書寫一個多分支的邏輯表達式,需要在其簡潔性和充分性之間做出平衡。因此,還是需要學生對計算機原理和工作方式有準確的理解。
3思維深度的推動
在教學中,學生往往看例題容易理解,而自己動手卻步履維艱,究其原因主要是還沒有具備科學抽象能力以及沒有掌握將理論應用于實踐的方法,對所學知識的認識和思維達到一定程度時就難以深入下去。程序設計是一種高強度的腦力勞動,程序代碼是算法的語言實現,而算法是經驗和思維的結果。我們人類的思維方式主要分為兩類,一是形象思維,二是抽象思維。通常人們總是認為程序設計是基于抽象思維的勞動。然而,越是強調其抽象性,學生越感覺學習困難。實際上,程序在計算機中運行是一個物理的工作過程,而算法又來源于物質的現實世界。在抽象邏輯的背后有著具象的問題和環境,有著容易認識和掌握的形象化技術和方法。如果從形象思維入手,經過一段過渡再到抽象思維,則會有事半功倍之效。
形象思維的運用方式是以具體事例為載體,對事物的屬性和活動進程做直觀式思考。特別是對于計算機程序,可以設想其執行過程,把它看作具有運動性的事物,這和數學方法解決問題是大不相同的。程序尚未執行時即可形容和感知程序中的每一條指令的執行結果和程序邏輯的運動軌跡,甚至程序還未形成,流程已在腦中,在此基礎上再進一步尋找和篩選最合適的條件和算法要素以解決問題。例如程序中處理的數據應具有離散特性,對離散數據的處理有一套基本方法,最初始的例子是采用循環遞推的方法計算自然數前n項和或者是n!。在這類算法中,自然是以循環語句為主體,這時,一條循環語句是高度抽象的,但其執行過程必須分解為n次基于存儲單元(變量)的運算,這又回歸到自然的手工方法且是形象化的。這種基于形象思維的學習方法適合于初學階段,特別是學習程序樣例時幫助理解教材中給出的程序代碼。如果學生把自己比做運行程序的計算機,在程序的執行過程中感知其動力、目的和成敗,則能進一步理解程序邏輯與執行結果的關系。
度過初級階段后,設計算法和編寫代碼描述出算法的內容,是進一步的抽象思維所要解決的問題。抽象思維的主要特征是以概念為載體,對概念進行思考,進行概括、描述、推導等活動。程序設計的思考過程是一個從形象到抽象的轉化過程,這一過程應基于科學抽象的基本方法。科學抽象是指在思維中對同類事物去除其現象的、次要的方面,抽取其共同的、主要的方面,從而做到從個別中把握一般,從現象中把握本質的認知過程和思維方法[3]。在遞推計算的例子中,數據的表象是自然數,按數學方法抽取其本質則得到遞推式f(n)=f(n-1)+n,但從算法的角度來抽象,卻要離散化地表示為n從初值開始通過n=n+1逐步演變為終值。可見在不同的領域中,抽象的前提是基于一套相應的理論,例如在程序設計領域,這一理論基礎是本課程所學習的一套形式化語言及公理。
感性與理性,形象與抽象都有不同的層次。例如在程序中輸入輸出是不可或缺的,輸入輸出也稱為人機交互,而人并不出現在程序中,程序只能響應人的操作,這些操作又只能通過外部設備來傳達,所以代表人的模型抽象為交互介質,這是第一層抽象。在不同語言中還需要第二層抽象,如C語言中以文件形式表現各種外部設備。在程序設計語言這一層,語言本身的詞匯、語法和語句又是一種現象,在這個現象的背后又是一套基于符號、規則和變形理論的形式化方法。
在學習過程中,通過從形象化思維到抽象思維可以完成建立概念、掌握方法和形成理論的學習階段,進一步再將理論運用到實踐,解決多種問題(也稱為舉一反三)的學習階段還需要加深思維活動,否則學習將止步不前。那么如何推動第二階段的思維呢?在本課程的教學中,經驗主義會得到部分提倡,具體來說是將屬于感覺和直觀的內容提升為普遍的觀念、命題和規律。但問題的復雜性以及計算機系統和算法語言的局限性使經驗性結論也受到限制。可行的方法是提倡思辨的學習態度,具體方法是質疑和推論。一方面對前面的成果提出質疑,找出新的問題,另一方面運用歸納和分離方法找出不同問題和算法的相同點和差別點,經過判斷和分析推導出新的結論。例如在面向對象的程序設計中,通訊錄的設計和實現是一個常見的作業,學生們第一次設計方案普遍采用定義一個記錄類并建立對象數組,這是在記錄層次上的一次抽象。這種方案的缺點是將對象數組的元素作為基本訪問單位,數組的有效長度沒有被封裝,數據表的操作也是獨立的,這樣的程序很難維護。當引導學生們對這一方案進行分析后,許多同學改用符合線性表解決方案的復合類,即記錄結點類和表長度變量作為通訊錄類的數據成員,使數據表的操作被封裝在通訊錄類中,這是二次抽象,通過通訊錄類的對象間接訪問記錄類的對象。這樣一來,學生在作業中掌握了多層次抽象的基本方法。
思維是人的主觀意識,其正確性是個人無法保證的,對結果的檢驗顯得極為重要。軟件開發領域重視的算法驗證和程序驗證也需要引導學生學習運用。在教學中較為快速有效的方法是課堂上老師對學生的作品進行點評,學生進行討論并向著深入的方向繼續思考,從而認清錯誤及發生的原因,改進程序質量,同時能夠觀察到較高質量的作業并得以借鑒。
4外部的學習因素
在本課程中,教學效率與方法的傳授有很大關系。由于前后所學的知識點有相互關聯和貫穿使用的特點,需要引導學生運用多種方法對所學內容做細致地梳理。例如,運用相似識別法、比較分類法等。對同一個問題,找出不同解法,同一個解法,找出不同的語言描述工具;運用分類法做一個算法集錦,以積累編程經驗。雖然這些都是學習的基本方法,但如何運用大有講究。
學生的心理因素和視覺因素也會影響到學習效果。例如,程序代碼的書寫風格往往是初學者不重視的,但是按照公認的良好風格書寫程序代碼,會使程序看上去具有一種美感。程序的美是一種科學美,不易被查覺,特別是程序代碼文本,只有喜愛編程的人才會認為它是美的。量子物理學家海森堡(Heisenberg)曾說:“美對于發現真理的重要意義在一切時代都得到承認和重視[4]”。我們通過對學生書寫代碼提出風格的要求,試圖使學生認識到,編寫具有美感的程序代碼,也是學習程序設計的一個必要條件,當他能夠看出程序的美就可以認為自己是入門了,這在他的心理上會產生一定的自信心。其實,良好的程序代碼風格只是一種外在美,它其實是程序內在的合理邏輯的體現,合理且通順的邏輯會自然地具有一種和諧的美,因為它是編程者的成功思維結果,這本身就令人內心感到美好和興奮。良好風格的程序源代碼具有層次性、呈現出一種結構美,具有簡潔性、統一性、對稱性、協調性以及思辨性。對程序風格的習慣性會提高人的編程直覺能力,這也是從一個角度體現經驗提高了能力。
5結語
實施以上教學實踐之后,筆者發現近幾年能夠較快入門的學生比例不斷提高,學生對參與討論和完成作業的積極性也非常高,特別是越來越多的學生熱衷于嘗試老師增加的具有應用意義的補充題,感覺到了學習本課程的樂趣。在教學的成敗問題上,教師的理念至關重要,理念的進步與更新也是一個不斷學習的過程。本文只是較為粗淺的探索,今后還需繼續努力更新和完善,使本課程的教學工作更上一層樓。
參考文獻:
[1] 教育部高等學校計算機科學與技術教學指導委員會. 程序設計基礎課程教學實施方案[J/OL]. [2009-10-01]. http:// computer.cncourse.com/computer/html/ejournal/2010_03/Program_wlx/index.html.
[2] 酈全民. 用計算的觀點看世界[M]. 中山:中山大學