李向華, 王震, 高超
1.西北工業(yè)大學(xué) 光電與智能研究院,西安 710000;2.西北工業(yè)大學(xué) 網(wǎng)絡(luò)空間安全學(xué)院,西安 710000
瑞士計算機(jī)科學(xué)家尼古拉斯.沃斯(Niklaus Wirth)提出的影響深遠(yuǎn)的“算法+數(shù)據(jù)結(jié)構(gòu)=程序”(Algorithm+Data=Programs)[1]公式,成為計算機(jī)科學(xué)特別是軟件科學(xué)的指導(dǎo)思想,同時這個公式也說明了程序設(shè)計語言和數(shù)據(jù)結(jié)構(gòu)這兩門課程之間的關(guān)系[2].
C程序設(shè)計和數(shù)據(jù)結(jié)構(gòu)是計算機(jī)相關(guān)專業(yè)兩門非常重要的基礎(chǔ)必修課.利用C語言實現(xiàn)的數(shù)據(jù)結(jié)構(gòu)必然以C程序設(shè)計為先導(dǎo)課程,利用C語言具體表達(dá)數(shù)據(jù)在計算機(jī)中的存儲和算法實現(xiàn).學(xué)生對數(shù)據(jù)結(jié)構(gòu)相關(guān)知識的學(xué)習(xí),不僅理解了數(shù)據(jù)結(jié)構(gòu)、算法和程序之間的關(guān)系,也是對C語言知識的鞏固和深化,使學(xué)生具有解決實際問題的能力.所以,C程序設(shè)計和數(shù)據(jù)結(jié)構(gòu)關(guān)系緊密,在一定程度上影響學(xué)生對計算機(jī)學(xué)科的學(xué)習(xí)興趣.然而,筆者在翻閱大量的C程序設(shè)計相關(guān)教材時發(fā)現(xiàn),C語言課程過多注重其語法體系,授課教師也基本按照教材的流程進(jìn)行講解,因此,很多學(xué)生學(xué)習(xí)過C語言后,不了解其實際應(yīng)用效果,也不能順暢地編寫程序.在學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)課程過程中,無論算法設(shè)計還是程序書寫上,尤其涉及到指針部分,學(xué)生都覺得晦澀難懂,不會靈活應(yīng)用,上機(jī)實踐時更是無從下手.這些現(xiàn)象說明教師在講授C語言和學(xué)生在學(xué)習(xí)C語言的過程中沒能結(jié)合適應(yīng)數(shù)據(jù)結(jié)構(gòu)的方法.
基于此,有必要在C語言的教學(xué)中,為數(shù)據(jù)結(jié)構(gòu)課程的開展做些鋪墊,讓學(xué)生在一種輕松、有興趣的氛圍中學(xué)習(xí),讓數(shù)據(jù)結(jié)構(gòu)變成相對容易學(xué)習(xí)的學(xué)科.同時,通過C語言的學(xué)習(xí),培養(yǎng)學(xué)生的邏輯思維能力、算法設(shè)計能力和創(chuàng)新能力[3-5].
C語言課程的內(nèi)容主要圍繞結(jié)構(gòu)化程序設(shè)計展開,即順序、選擇、循環(huán)三個基本結(jié)構(gòu)[6-7],為了能實現(xiàn)這三種結(jié)構(gòu),前期要學(xué)習(xí)數(shù)據(jù)類型、輸入輸出語句等,為了處理稍復(fù)雜的問題,后期在三種結(jié)構(gòu)的基礎(chǔ)上學(xué)習(xí)函數(shù)、數(shù)組、指針、結(jié)構(gòu)體、文件等.C語言課程的主要內(nèi)容如圖1所示,其中箭頭表示授課的先后順序.它與數(shù)據(jù)結(jié)構(gòu)的關(guān)系如圖2所示.
根據(jù)圖2可以看出,數(shù)據(jù)結(jié)構(gòu)課程主要講授兩大類數(shù)據(jù)在計算機(jī)中的存儲和實現(xiàn),即線性數(shù)據(jù)(線性表、棧、隊列、串等)和非線性數(shù)據(jù)(樹、圖等)[8-9],主要操作是數(shù)據(jù)的增、刪、改、查.其中線性存儲結(jié)構(gòu)是非線性結(jié)構(gòu)的基礎(chǔ),而線性結(jié)構(gòu)的基礎(chǔ)又是C語言中的數(shù)組、指針、函數(shù)和結(jié)構(gòu)體,故而應(yīng)在學(xué)習(xí)C語言的過程中把這幾部分知識重點講解,讓學(xué)生多加練習(xí),學(xué)精學(xué)透.如此,學(xué)生們在進(jìn)行數(shù)據(jù)結(jié)構(gòu)的學(xué)習(xí)后,會順利過度,無縫銜接,也會進(jìn)一步提升學(xué)生們的學(xué)習(xí)興趣和解決實際問題的能力.因此,教師在講授C語言的過程中,必須有所側(cè)重、有的放矢,為學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)做好準(zhǔn)備.
圖1 C程序設(shè)計主要內(nèi)容
圖2 C語言相關(guān)內(nèi)容與數(shù)據(jù)結(jié)構(gòu)之間的關(guān)系
從如何學(xué)好數(shù)據(jù)結(jié)構(gòu)這門課程來看,目前的C語言教學(xué)過程中存在如下主要問題:
(1) 總體來看,過于注重語法體系,實驗課內(nèi)容淺顯.C語言是學(xué)生接觸到的第一門程序設(shè)計語言,而學(xué)生的學(xué)習(xí)精力大多用在簡單程序的編寫上.教學(xué)過程中發(fā)現(xiàn),在循環(huán)結(jié)構(gòu)學(xué)習(xí)之前,絕大部分同學(xué)都能跟上節(jié)奏,然而當(dāng)循環(huán)、函數(shù)、數(shù)組、指針、結(jié)構(gòu)體等內(nèi)容展開后,開始陸續(xù)有學(xué)生掉隊.這說明我們在平時的授課和實驗過程中,對相對難點投入的時間和深度不夠,使得學(xué)生在處理復(fù)雜問題時缺乏經(jīng)驗和能力.而數(shù)據(jù)結(jié)構(gòu)的學(xué)習(xí)又恰恰以數(shù)組、函數(shù)、指針和結(jié)構(gòu)體為基礎(chǔ),這個環(huán)節(jié)的薄弱導(dǎo)致了學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)不能得心應(yīng)手.
(2) 從具體內(nèi)容來看,存在如下問題:
①從C語言到數(shù)據(jù)結(jié)構(gòu)命名形式的跳變.在C語言的教學(xué)過程,雖然講授了變量、函數(shù)名等的命名規(guī)則,如做到見名知意、駝峰命名法等,但因為教材中的例題簡單,采用的命名法也相對簡易,如變量名和數(shù)組名用a、b、c等,函數(shù)名使用f1、f2等.雖然對初學(xué)者來說,這樣的命名簡單、易寫,但是過渡到數(shù)據(jù)結(jié)構(gòu)中,卻非常不適應(yīng),仿佛學(xué)的是兩種語言.如數(shù)據(jù)結(jié)構(gòu)中初始化線性表的函數(shù)名InitList_Sq,建立鏈表的函數(shù)名為CreateList_L,圖的頂點數(shù)目常量MAX_VERTEX_NUM等.在數(shù)據(jù)結(jié)構(gòu)中的變量和函數(shù)名雖然稍顯復(fù)雜,但真正做到了見名知意,增加了程序的可讀性.
②指針內(nèi)容講授過于泛化.眾所周知,指針是C語言的核心和精華,指針的使用除了可以使程序簡潔、緊湊和高效外,有些情況非用指針不可,比如數(shù)據(jù)結(jié)構(gòu)中鏈表、樹、圖的構(gòu)建.在有些無法用值傳遞完成的問題中,可以用指針來完成,如在子函數(shù)中完成兩個數(shù)的交換.然而,在C語言的教學(xué)中,根據(jù)教材內(nèi)容講授往往淺顯且寬泛,并無針對性地重點講指針的具體應(yīng)用,給學(xué)生的感受是指針可用可不用,指針麻煩難懂,可被替代,完全沒有體會出其精髓所在,過度到數(shù)據(jù)結(jié)構(gòu)時,老師又花費大量時間幫助學(xué)生理解指針的用法和妙處,增加了數(shù)據(jù)結(jié)構(gòu)學(xué)習(xí)的難度.
③結(jié)構(gòu)體部分的講解過于簡略.在C語言的學(xué)習(xí)過程中,由于課本例題、習(xí)題以及實驗內(nèi)容偏簡單,似乎不用太多結(jié)構(gòu)體的知識,加之課時有限,很多老師就把該部分作為略講和選講的內(nèi)容,以至給學(xué)生帶來結(jié)構(gòu)體不重要的錯覺.然而結(jié)構(gòu)體在數(shù)據(jù)結(jié)構(gòu)的學(xué)習(xí)過程中,貫穿始終,有時候還層層嵌套,比如圖的鄰接表的存儲表示[9],如圖3所示.
圖的實現(xiàn)屬于數(shù)據(jù)結(jié)構(gòu)中偏后部分的知識,但仍有部分同學(xué)不能很好地理解這種嵌套的結(jié)構(gòu)體,都是源于C語言基礎(chǔ)薄弱.
圖3 結(jié)構(gòu)體在數(shù)據(jù)結(jié)構(gòu)中重要性示例
④算法設(shè)計思想薄弱.在C語言的學(xué)習(xí)過程中,由于內(nèi)容比較淺顯,例題、練習(xí)題和實驗內(nèi)容都比較簡單,所以同學(xué)們算法設(shè)計思想淡薄.雖然學(xué)習(xí)了流程圖,但幾乎在整個C語言的學(xué)習(xí)過程中沒有用到,致使學(xué)生們養(yǎng)成了遇到問題沒有過多的思考和設(shè)計就直接編碼的習(xí)慣,結(jié)果形成了編了刪、刪了再編的低效率學(xué)習(xí),也使得同學(xué)們在學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)的過程中,由于問題的復(fù)雜,而變得束手無策,算法設(shè)計不成體系.
為了解決上述在C語言教學(xué)中存在的問題,現(xiàn)提出以下對應(yīng)整改措施.
(1) 總體上側(cè)重實際應(yīng)用.由于以往C語言的教學(xué)過程中,程序相對簡單,所以學(xué)生在編寫過程中會存在這樣的困惑,編寫這樣的程序有什么用?有些老師還會花費大量時間去講解在實際應(yīng)用中使用率不高的語法點,導(dǎo)致學(xué)生的學(xué)習(xí)熱情不高.所以,我們應(yīng)該以解決實際問題為出發(fā)點,以問題為導(dǎo)向開展C語言的教學(xué).比如講解變量的數(shù)據(jù)類型時,不用面面俱到,只講最常用和實用的int、float、double、char的基礎(chǔ)知識;講解自增、自減運算符時,只介紹i++(i--)和++i(--i)的區(qū)別即可,其余知識請學(xué)生自學(xué);在講解輸入輸出語句時,也只講解最為常用的幾對輸入輸出語句即可,如printf和scanf、putchar和getchar、puts和gets等,在實際應(yīng)用中再次強(qiáng)化.這樣,我們利用較少的時間學(xué)習(xí)最實用的這部分基礎(chǔ)知識,結(jié)余出更多時間去學(xué)習(xí)后面的循環(huán)、數(shù)組、函數(shù)和指針等難點部分,為數(shù)據(jù)結(jié)構(gòu)的學(xué)習(xí)打好基礎(chǔ).
(2) 具體內(nèi)容來看,措施如下:
①養(yǎng)成良好的編程風(fēng)格.既然C語言是學(xué)生接觸到的第一門編程語言,那它也擔(dān)負(fù)著學(xué)生習(xí)慣養(yǎng)成的重大使命.這個習(xí)慣主要是指算法設(shè)計和編寫可讀性強(qiáng)的程序.面對復(fù)雜問題時,我們要培養(yǎng)學(xué)生化繁為簡、有步驟各個擊破的思想,即利用函數(shù)解決一個個小問題,每個函數(shù)只實現(xiàn)一個子功能.由于函數(shù)的高內(nèi)聚性,設(shè)計它就變得容易了.
編寫可讀性強(qiáng)的程序則要求學(xué)生們做到以下幾點[10]: a. 注意程序的視覺組織,采用階梯縮進(jìn)形式使程序結(jié)構(gòu)清晰明顯;b. 變量、函數(shù)的命名做到見名知意;c. 給每個函數(shù)加序言性注釋,重要的變量、語句等加解釋性注釋.
例如圖4所示的代碼[11],雖然功能簡單,但可讀性強(qiáng).這樣的編程風(fēng)格,更加有利于學(xué)生們過渡到數(shù)據(jù)結(jié)構(gòu)的學(xué)習(xí)中.
圖4 程序可讀性舉例
②指針部分重點講解與數(shù)據(jù)結(jié)構(gòu)結(jié)合強(qiáng)的知識點.指針是C語言中的重點和難點,然而在C語言的教學(xué)過程中,過多地注重了指針的語法,而非應(yīng)用.在C語言的大部分教材中,有一節(jié)詳細(xì)地講述了一維數(shù)組、二維數(shù)組與指針的關(guān)系,以及指針數(shù)組和數(shù)組指針,給學(xué)生的體會是指針并無太大用處,是否使用指針都可以實現(xiàn)數(shù)組的操作.為避免學(xué)生們對指針認(rèn)知上的偏差,除了指針的基礎(chǔ)知識外,我們應(yīng)該花大量篇幅去學(xué)習(xí)必須使用指針的情況、指針與函數(shù)的關(guān)系、動態(tài)內(nèi)存分配中涉及到的指針知識以及結(jié)構(gòu)體與指針.站在利用數(shù)據(jù)結(jié)構(gòu)解決實際問題的角度,指針貫穿始終,從順序結(jié)構(gòu)的鏈表到層次結(jié)構(gòu)的樹和網(wǎng)狀結(jié)構(gòu)的圖,沒有指針難以實現(xiàn).以鏈表為例,鏈表節(jié)點的定義包括了指針與結(jié)構(gòu)體的關(guān)系;鏈表的創(chuàng)建除了指針與結(jié)構(gòu)體的關(guān)系,還包括了指針與動態(tài)分配內(nèi)存的關(guān)系;鏈表的刪除包括了指針與函數(shù)的關(guān)系等.總之,指針的重要作用無可取代,所以我們應(yīng)該重點講授與數(shù)據(jù)結(jié)構(gòu)存儲相關(guān)的指針知識點,可適當(dāng)滲透數(shù)據(jù)結(jié)構(gòu)相關(guān)知識,引起學(xué)生興趣與重視.
③結(jié)合數(shù)據(jù)結(jié)構(gòu)的順序表學(xué)習(xí)數(shù)組和結(jié)構(gòu)體.數(shù)據(jù)結(jié)構(gòu)中的順序表本質(zhì)結(jié)構(gòu)是一維數(shù)組,但通過動態(tài)申請獲得空間,利用結(jié)構(gòu)體整合數(shù)組,同學(xué)們會覺得晦澀難懂,這都源于C語言學(xué)習(xí)過程中老師未曾從數(shù)據(jù)結(jié)構(gòu)角度進(jìn)行講解.所以,當(dāng)學(xué)生們學(xué)完基本的數(shù)組基礎(chǔ)知識后,可以適當(dāng)擴(kuò)充,數(shù)組不僅可以靜態(tài)產(chǎn)生,也可以動態(tài)申請,而且動態(tài)申請的空間彌補(bǔ)了靜態(tài)不能動態(tài)增長的弊端.數(shù)組的學(xué)習(xí)也可以引出結(jié)構(gòu)體相關(guān)知識,例如有些實際問題不能預(yù)估具體數(shù)據(jù)量,故會定義較大數(shù)組存儲少于數(shù)組長度的數(shù)據(jù),使得數(shù)組中實際數(shù)據(jù)個數(shù)與該數(shù)組息息相關(guān),這樣我們就可以把數(shù)組和它的實際長度封裝在一起,利用結(jié)構(gòu)體實現(xiàn).通常情況下,在C語言的教材中,動態(tài)申請空間的兩個函數(shù)malloc和remalloc以及結(jié)構(gòu)體都是放在最后面學(xué)的,講解也比較粗略,學(xué)生們也沒有應(yīng)用場景,自然體會不到它們的真正作用.
經(jīng)過把順序表和數(shù)組學(xué)習(xí)的結(jié)合,讓同學(xué)們深切感受到了結(jié)構(gòu)體和動態(tài)申請空間函數(shù)的實際應(yīng)用,做到了有的放矢,能夠?qū)W以致用,更能提高學(xué)習(xí)興趣.同時,也可以把書上的例題和習(xí)題按動態(tài)申請數(shù)組空間和利用結(jié)構(gòu)體封裝的思想再練習(xí)一遍.這樣,學(xué)生們學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)時候就會銜接順利,再學(xué)習(xí)棧、隊列的時候也更得心應(yīng)手.
④強(qiáng)化算法設(shè)計思想.如果我們在學(xué)習(xí)和講授C語言的過程中,注重實際應(yīng)用且執(zhí)行上述措施,學(xué)生潛移默化中就有了算法設(shè)計的思想.在講解具體題目時,除了自然語言描述算法思想外,教師再配以流程圖、偽碼等描述算法的工具,學(xué)生慢慢就會養(yǎng)成先思考、再編程的習(xí)慣.
鑒于學(xué)生們對學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)的迷茫和畏難心里,我們需要從根本上解決問題,即把其基礎(chǔ)——C語言程序設(shè)計學(xué)透、學(xué)牢.故本文針對C語言教學(xué)中存在的主要問題加以分析并給出了相應(yīng)的解決措施.此外,本人通過走訪、調(diào)研學(xué)生心聲發(fā)現(xiàn),絕大多數(shù)學(xué)生希望這兩門課程由一名教師授課,形成兩學(xué)期課程的連續(xù)性.
本文所闡述的內(nèi)容不是在C程序設(shè)計過程中簡單地添加數(shù)據(jù)結(jié)構(gòu)知識,而是以數(shù)據(jù)結(jié)構(gòu)為導(dǎo)向的深入學(xué)習(xí)C語言知識,并滲透數(shù)據(jù)結(jié)構(gòu)算法的思想,同時培養(yǎng)學(xué)生的邏輯思維能力和創(chuàng)新能力.故對學(xué)生的考核應(yīng)以實際動手能力為主,合理選用教材.本人下一步的主要工作就是重新編寫融入數(shù)據(jù)結(jié)構(gòu)思想的C程序設(shè)計教材.