作為剛剛學(xué)習(xí)C的新手录别,水平較低,難免出錯邻吞。希望各位前輩不吝賜教组题,批評指正。
????在C語言學(xué)習(xí)了一段時間之后抱冷,我們開始入了課程設(shè)計崔列。初學(xué)了一些簡單的語法之后,感覺要完成一項工程還是有些困難的旺遮。
????聽說在寫課程設(shè)計時赵讯,比起一下子打出來完,不如分模塊耿眉,分功能的有步驟的去寫圆雁。
????課程設(shè)計的核心齐遵,是對鏈表的操作,實現(xiàn)動態(tài)鏈表的增、刪、改、查。這里主要說一下課程設(shè)計的思路和想法。
????對于鏈表的具體操作江滨,諸君都比我水平高,不敢贅言厌均,就簡單提一下唬滑。
1.顯示主菜單
在復(fù)雜面前,先做一些微不足道的小工作棺弊。先把菜單的內(nèi)容寫了出來晶密,在主函數(shù)里調(diào)動menu()就會出來這個直接顯示的界面。
????其實一開始镊屎,考慮到menu()只是用來顯示惹挟,我就把它定義成了void型,后來在學(xué)長的提醒下缝驳,把void改為了int连锯,原來在一些其他的編譯器里,void型被淘汰或者是會報錯用狱。為了養(yǎng)成良好的編程習(xí)慣运怖,就把剩下的void都改成了int或其他。
2.操作菜單
接下來夏伊,在操作菜單里摇展,填寫以下內(nèi)容 :
????這個就是提供一個選擇功能的途徑,至于功能溺忧,之后再補全咏连,總之先把位置留出來。
???通過輸入數(shù)字的方式來選擇功能鲁森,在1--8的范圍內(nèi)(圖中的printf是添加讀檔功能前的7個祟滴,不必在意),輸入正確就讓flag=1歌溉,如果輸入其他的垄懂,那就循環(huán)回來重輸。
????至于那個while里的判斷(真or假)痛垛,只要n不在1--8草慧,就一直為真,一直循環(huán)匙头,當然你要是高興漫谷,把(flag==0)換成(1)也行。
上一步對flag的操作蹂析,目的就是為了引出下面的循環(huán)舔示,在正確的選擇功能里朽寞,通過swich實現(xiàn)相關(guān)功能的函數(shù)調(diào)動,n也就是用到這里斩郎,當然在一開始并沒有這些函數(shù),我只是寫了printf和break而已喻频。
為了方便起見缩宜,我把switch里的內(nèi)容先折疊一下。
????在你選擇并實現(xiàn)了相關(guān)功能以后甥温,順序執(zhí)行锻煌,在125行進行詢問是否繼續(xù),并且通過getchar()來獲取一個字符姻蚓。如果y(yes)宋梧,再次獲取n,再次循環(huán)狰挡,周而復(fù)始捂龄。
???? 如果輸入其他的,那就直接退出了exit(0)加叁。
????(函數(shù)exit()通常是用在子程序中用來終結(jié)程序用的倦沧,要加上頭文件#include<stdlib.h>)。
3.創(chuàng)建鏈表
????說起創(chuàng)建鏈表它匕,大家都有自己的做法展融。我的做法就是定義了兩個結(jié)構(gòu)體指針,先共同賦了一片空間豫柬,為p1賦值告希,(圖中的sca就是我調(diào)動賦值的函數(shù))。其實再一開始烧给,我就聲明了一個全局變量:
????????????????struct work*head=NULL;
????在之后的對鏈表操作都是在對頭進行操作燕偶。讓鏈表停止的操作,就是在初始化時创夜,使工號為0杭跪。在第一個節(jié)點時,需要特殊處理一下驰吓,即令p和head指向同一片空間涧尿,這樣就能起到 拿起鏈表頭就能拿起一串的效果。
????之后的操作就司空見慣了檬贰,讓p1申請空間并賦值姑廉,再讓p2指向p1所開辟的新空間,循環(huán)往復(fù)的增加節(jié)點翁涤,直到工號為0時停止桥言。
最后萌踱,別忘了單鏈表的尾要置空。最后的返回值就是把“頭head”返回去了号阿,因而可以實現(xiàn)case 1里的 head=creat(head)了并鸵。
????*那個system("cls")是后來為了美觀加上的,在前期修改時為了及時的反饋問題扔涧,盡量不要加园担。
4.顯示節(jié)點和鏈表
剛剛做了一套貌似復(fù)雜的操作,現(xiàn)在我們來看一些輕松的東西枯夜。
在我們對鏈表進行操作時弯汰,難免要經(jīng)常查看節(jié)點和整個鏈表,要是每次都輸出的話那是多么的繁瑣湖雹,不如直接調(diào)動函數(shù)咏闪。我就寫了兩個方便自己查看的,一個是看單個節(jié)點如你所見摔吏,傳入?yún)?shù)結(jié)構(gòu)體指針鸽嫂,把每一個數(shù)據(jù)成員都顯示出來。
另一個是顯示整個鏈表征讲,把頭head傳進來溪胶,為了防止對head進行誤操作,臨時定義結(jié)構(gòu)體指針p稳诚。令p和head指向同一片空間哗脖,再通過 do-while 對p進行遍歷。在printnode()的基礎(chǔ)上輸出一個一個又一個的節(jié)點扳还。
5.增加
毫無疑問才避,這是這里面最簡單的功能操作。
????如你所見,為了圖方便俏让,我甚至都沒有去找最后的節(jié)點插入楞遏,而是就直接放到了頭結(jié)點的后面。反正就算只有一個節(jié)點也可以放到后面首昔。
6.查找
????除了增加以外寡喝,最簡單的就算是查找了,因為這個遍歷的過程勒奇,會是其他功能的基礎(chǔ)预鬓。
圖中for循環(huán)的過程,就是鏈表遍歷的過程赊颠,在一遍的搜索之后格二,如果出現(xiàn)的需要的東西劈彪,那就停止搜索,可以拿出來操作了顶猜。這里只是作為顯示沧奴,并不需要操作什么。
圖中的continue是考慮到會有工號重復(fù)的情況长窄。
7.刪除
????進入了刪除模式之后扼仲,會有兩個選項,按工號或者姓名刪除抄淑,其實原理都一樣,這里就以工號刪除為例驰后。
????令新的指針代替頭指針實現(xiàn)遍歷(213)肆资,判斷出來要刪除的節(jié)點之后,再進行一次判斷:你要刪除的灶芝,是頭結(jié)點郑原,還是其他的。
a.頭結(jié)點刪除:
????直接讓指針指向下一位夜涕,釋放掉原本的第一個犯犁,再讓頭指針重新指向原本的第二個。這里實現(xiàn)的過程就是pt比pt2多走了一位女器,以便進行操作酸役。
b.其他節(jié)點:
????直接令p2的后繼指向pt的后繼,也就是把pt直接隔過去驾胆,再進行釋放涣澡。
至于下面的if,如你所見丧诺,它的功能就是在while循環(huán)里入桂,使指針不斷向后推進,直至目標出現(xiàn)驳阎。
????當然了抗愁,按姓名刪除的操作幾乎一模一樣,唯一的一點小區(qū)別就是呵晚,if的判斷變成了這樣:
????????if( strcmp(name,pt->name)==0 )
需要判斷這兩個字符串是否一致蜘腌,完全一致的話,返回值就是0了饵隙,就能找到該節(jié)點了逢捺。strcmp需要頭文件<stdlib.h>.
7.修改
????寫之前感覺修改會很難,大概是不小心走了什么歪門邪道吧癞季,寫出來發(fā)現(xiàn)它的過程和遍歷一樣簡單劫瞳,無非是在我找到相關(guān)pt之后倘潜,又為它重新賦值了一遍而已(你當然會記得那個sca是我之前定義的賦值函數(shù))。
排序!
????如果你特別熟練鏈表以及它的增刪改查志于,那么前面寫的實在是基礎(chǔ)涮因。而排序的確讓我為難困惑了一番。
a.冒泡的錯
????再最開始版本的排序里伺绽,我嘗試了用冒泡排序?qū)ぬ栠M行操作养泡,排的過程也比較簡略∧斡Γ可排出來之后感覺哪里好像有點不對澜掩,原來當時只是把num排了順序,結(jié)果是其他的就亂了杖挣。如你所見肩榕,它繁瑣而低效(關(guān)鍵是還不對...)。
????其實當時忘了一點惩妇,為什么不直接聲明一個結(jié)構(gòu)體變量株汉,然后把它當做中間變量進行排序呢?
b.選擇排序
并沒有順著那個思路想下去歌殃,換了個方法乔妈。
????思想:如果說,原本的鏈表是無序的氓皱,而我最終的目的是創(chuàng)造出有序的路召。而且我有能力去找到這里面最大的或最小的(遍歷就可以了),那么我何不再去創(chuàng)建一個新的鏈表波材,它是由原本鏈表摘出來的節(jié)點所組成优训,那必然是有序的。
????和其他操作的最開始一樣各聘,傳入了頭和它之后的一串鏈表揣非,于以往不同的是,這次開始了直接對頭指針的操作躲因。
(366和367是為了防止傳進來一個空頭造成錯誤早敬。
核心代碼就是white里的循環(huán)了:
第一層循環(huán)
????目的是為了讓頭不斷向后遍歷,只不過這次的目的大脉,就是遍歷到終點搞监。期間每執(zhí)行一次,就讓我定義的指針重新指向同一塊镰矿。
第二層循環(huán)
????p(也就是頭)的遍歷琐驴,如果后一個大于前一個,就讓后一個成為max,同時定位它的前一個節(jié)點绝淡,以這種方式標記過后宙刘,p再繼續(xù)向后推進,以實現(xiàn)在循環(huán)過后牢酵,可以過濾出來最大的悬包,找到了又怎樣呢,我們來看接下來的操作馍乙。
第一個if(379)
????這時還要考慮到那種情況布近,也就是頭結(jié)點萬一最大該怎么操作,這也并不難想丝格,直接讓head指向下一位撑瞧,同時斷開max(也就是頭)與原鏈表的聯(lián)系。
其它情況就是显蝌,既然上一步(371 while)找出來了max预伺,那么就在這里把它摘出來,令剛剛標記的前一項(pre)指向max的后繼琅束,在斷開max與原表的聯(lián)系。
第二個if(387)
????細心的你會發(fā)現(xiàn)算谈,在每次的賦值里和之前的幾步操作里涩禀,都沒有用到pnew,不僅如此然眼,它還在一開始就被置空了艾船。
我的目的就是讓它成為那個新的鏈表的頭。在之前幾步高每,我們分別找到了max屿岂,分離出了max,終于要在這一步為max找一個著落了鲸匿。
????當然爷怀,if第一次肯定是會執(zhí)行的(因為上來就讓pnew置空了),我們讓最大的那個節(jié)點成了新鏈表的第一個带欢,那么可想而知的是运授,在之后幾次的循環(huán)里,每次都會執(zhí)行else乔煞,并且在里面新摘出來的max被一個個的連到了鏈表的后面吁朦。
????到最后,別忘了還有那個大循環(huán)的渡贾,它每次執(zhí)行一遍里面的內(nèi)容逗宜。如是,原本的無序鏈表每次少一個節(jié)點(最大的節(jié)點),而新有序鏈表每次會多一個纺讲。
????原鏈表終結(jié)之日擂仍,也就是新鏈表生成之時。屆時刻诊,循環(huán)也就徹底結(jié)束了防楷,于是我們令頭指針指向那個新生鏈表(394),再讓它們共同指向這條有序的鏈表则涯,傳回去就行了复局。
????到了這里,課程設(shè)計也就基本上結(jié)束了粟判,增刪改查帶排序都說完了亿昏,如果你覺得意猶未盡,我們的學(xué)長學(xué)姐提出了一個新的要求:
????該怎么做档礁,才可以讓你的數(shù)據(jù)保存下來角钩,讓我下次打開時還能看到這次的數(shù)據(jù),下次開機時它們還在這里呻澜?
emmm....
對文件的操作
????在學(xué)文件的時候递礼,我總覺得這塊的內(nèi)容可以在今后用到的時候及搜及學(xué)。要實現(xiàn)如上功能羹幸,需要fwrite和fread :
(1)size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
其中脊髓,ptr:指向保存結(jié)果的指針;size:每個數(shù)據(jù)類型的大姓な堋将硝;count:數(shù)據(jù)的個數(shù);stream:文件指針
函數(shù)返回讀取數(shù)據(jù)的個數(shù)屏镊。
(2)size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
其中依疼,ptr:指向保存數(shù)據(jù)的指針;size:每
個數(shù)據(jù)類型的大卸妗律罢;count:數(shù)據(jù)的個數(shù);stream:文件指針
函數(shù)返回寫入數(shù)據(jù)的個數(shù)棍丐。
舉個小例子:
fwrite(p,sizeof(int),1,fp )
????這就是個每次向fp里存一個整型的弟翘,p就是那個要存到文件里的指針。
read同理骄酗,不表稀余。
????原本是要在每個功能的后面都加上這么一個寫入文件的,后來在學(xué)長的提醒下趋翻,把最后一個功能改成了“保存并退出”睛琳,合理了不少。
save
????如我這個save函數(shù):fopen打開,司空見慣师骗。利用for循環(huán)历等,使pt從頭到尾的指一遍,每次把一個struct work存進去辟癌,也就是一個節(jié)點寒屯,以這種方式把整條鏈表存進去。
read
????你會發(fā)現(xiàn)黍少,這是個沒有穿入?yún)?shù)的結(jié)構(gòu)體函數(shù)寡夹,在直至文件fp的結(jié)尾之前,一直進行著循環(huán)厂置。fread的返回值是寫入數(shù)據(jù)的個數(shù)菩掏,也就是說每次從文件里面讀一個,直到最后一個.
else的作用是把每一個節(jié)點都顯示出來昵济,顯得有那么一點合情合理...
那每次讀出來的節(jié)點都去了哪里呢智绸?
????這個和剛剛說的排序思路差不多,讓head指向和pt一樣的空間后访忿,循環(huán)申請空間瞧栗,每次都存入一個從文件里讀出來的節(jié)點。形成了一條以head為頭的新的鏈表(也就是上次你退出時的數(shù)據(jù))海铆,被傳回來得以繼續(xù)操作迹恐。
????這樣,你也就得到了一個游添,可以增刪改查排序的系草,還能記
錄數(shù)據(jù)的課程設(shè)計了通熄。
寫課程設(shè)計唆涝,對于初學(xué)者來說是個漫長而復(fù)雜的過程,一籌莫展和萬念俱灰的想法總是交相輝映唇辨。雖然有時也會絕望(比如我第一次運行有好幾十個錯誤)廊酣,但這就是個從中學(xué)習(xí)的過程。
把代碼一點一點的改對赏枚,是個愉悅而有成就感的事亡驰。
last but not least :
感謝敏學(xué)姐、浪浪學(xué)長的指導(dǎo)和審閱饿幅,祝學(xué)長和429學(xué)長的鼓勵支持凡辱。
感謝圖書館,提供了幾乎所有知識栗恩。