
課程設(shè)計(jì)
編號(hào):
學(xué)號(hào):2
教學(xué)院計(jì)算機(jī)學(xué)院
課程名稱數(shù)據(jù)結(jié)構(gòu)課程設(shè)計(jì)
題目簡易家譜系統(tǒng)
專業(yè)計(jì)算機(jī)科學(xué)與技術(shù)
班級(jí)(1)班
姓名陳建輝
同組人員周海濤,石義灃,明廷柱
指導(dǎo)教師程細(xì)才
2013年1月8日
課程設(shè)計(jì)(論文)
1
目錄
一概述..................................................2
1.課程設(shè)計(jì)的目的......................................2
2.課程設(shè)計(jì)的要求......................................2
二總體方案設(shè)計(jì)..........................................3
1.簡單家譜系統(tǒng)整體設(shè)計(jì)思路............................3
2.簡單家譜系統(tǒng)的主要特點(diǎn)及功能.......................5
三詳細(xì)設(shè)計(jì)..............................................7
1.查詢?nèi)康募易V成員信息.............................7
2.確定指定成員在家族中的輩份..........................7
3.在家譜中添加新成員,并追加到文件中..................9
四程序的調(diào)試與運(yùn)行結(jié)果說明.............................12
1.實(shí)驗(yàn)結(jié)果截圖:......................................12
2.調(diào)試時(shí)遇到的問題..................................12
五課程設(shè)計(jì)總結(jié).........................................13
附錄一:程序源代碼.......................................16
附錄二:參考文獻(xiàn).........................................25
課程設(shè)計(jì)(論文)
2
一概述
1.課程設(shè)計(jì)的目的
1.理解和掌握該課程中的有關(guān)基本概念,程序設(shè)計(jì)思想和方法。
2.培養(yǎng)綜合運(yùn)用所學(xué)知識(shí)獨(dú)立完成課題的能力。
3.培養(yǎng)勇于探索、嚴(yán)謹(jǐn)推理、實(shí)事求是、有錯(cuò)必改,用實(shí)踐來檢驗(yàn)理論,
全方位考慮問題等科學(xué)技術(shù)人員應(yīng)具有的素質(zhì)。
4.掌握從資料文獻(xiàn)、科學(xué)實(shí)驗(yàn)中獲得知識(shí)的能力,提高學(xué)生從別人經(jīng)驗(yàn)中
找到解決問題的新途徑的悟性,初步培養(yǎng)工程意識(shí)和創(chuàng)新能力。
2.課程設(shè)計(jì)的要求
設(shè)計(jì)要求:輸入家族成員情況,建立樹結(jié)構(gòu),統(tǒng)計(jì)家族成員人數(shù),能查詢
家族成員輩份情況。
系統(tǒng)功能:
1.輸入、修改與刪除家譜信息功能
2.查詢功能:
1)某家譜成員的所有子孫的集合
2)某家譜成員的所有祖先的集合
3)某家譜成員的所有同輩成員的集合
4)求某家譜成員的所有上一輩成員的集合
5)給出兩個(gè)家譜成員,確定他們的關(guān)系
課程設(shè)計(jì)(論文)
3
二總體方案設(shè)計(jì)
1.簡單家譜系統(tǒng)整體設(shè)計(jì)思路
此次課程設(shè)計(jì)的整體思路是采用遍歷算法,整個(gè)樹的定義使用兩個(gè)結(jié)
構(gòu)體來表示,一個(gè)結(jié)構(gòu)體專門用于存放每一個(gè)節(jié)點(diǎn)的信息,另一個(gè)節(jié)點(diǎn)中
定義了三個(gè)指針域,分別為父指針域(兄長指針域),兄弟指針域,子指針
域,整個(gè)樹的輸入采用文件導(dǎo)入的方式,首先將文件導(dǎo)入到樹中,文件包
含每一個(gè)家族成員的信息,以及一個(gè)標(biāo)志位flag,標(biāo)志位的值為0,1,2,0
表示此節(jié)點(diǎn)沒有兄弟節(jié)點(diǎn),1表示此節(jié)點(diǎn)至少有一個(gè)子節(jié)點(diǎn),2表示此節(jié)點(diǎn)
至少有一個(gè)兄弟節(jié)點(diǎn),使用的算法是先定義一個(gè)鏈?zhǔn)疥?duì)列,將文件中第一
個(gè)節(jié)點(diǎn)的內(nèi)容讀取放入開辟的樹的節(jié)點(diǎn)的空間里,然后將樹節(jié)點(diǎn)放入隊(duì)列
中,此時(shí)隊(duì)列不為空,以隊(duì)列不為空為判斷條件,進(jìn)行while循環(huán),判斷
flag的值,循環(huán)體中再進(jìn)行文件讀取,循環(huán)中進(jìn)行判斷,若flag為0,則
繼續(xù)判斷隊(duì)列是否為空,為空就結(jié)束循環(huán),若不為空,則繼續(xù)出隊(duì)列,取
標(biāo)志位進(jìn)行判斷,若標(biāo)志位為1,則生成新節(jié)點(diǎn),用剛剛出列的節(jié)點(diǎn)的子指
針域進(jìn)行指向新節(jié)點(diǎn),新節(jié)點(diǎn)的父指針域指向出列的節(jié)點(diǎn),剩余的域?yàn)榭眨?/p>
然后將新生成的節(jié)點(diǎn)插入到隊(duì)列中,若flag為1,則進(jìn)行兄弟節(jié)點(diǎn)的插入,
繼續(xù)循環(huán),若flag不為0,則在進(jìn)行判斷,若為2,則繼續(xù)進(jìn)行兄弟節(jié)點(diǎn)
的插入,以此類推,根據(jù)文件的讀取,將樹生成,本程序中所有的算法都
基于以上所介紹的算法。
關(guān)于IO的設(shè)計(jì):
考慮到題目要求家譜信息以樹形的形式一次讀入內(nèi)存,而個(gè)人的各種資
料現(xiàn)在雖然條目不多,但隨著程序的升級(jí),以后可能變得越來越大。
我把樹形結(jié)構(gòu)和個(gè)人信息記錄的文檔分為兩個(gè)文件保存在外存中,一個(gè)文
件串行化地記錄家譜樹的結(jié)構(gòu)信息,保存少量個(gè)人信息作為識(shí)別標(biāo)志;另
一個(gè)文件保存完整的個(gè)人信息,所有的個(gè)人信息以線性記錄的方式記錄在
其中。當(dāng)程序運(yùn)行要讀入家譜結(jié)構(gòu)時(shí),只讀入保存少量記錄的文件并建立
起樹形結(jié)構(gòu)。索引時(shí),以樹形中的少量信息為依據(jù)在另一個(gè)文件中找到全
部的各人信息資料。
這樣的好處主要有兩點(diǎn):
1.由于樹形結(jié)構(gòu)是串行化記錄于外存,一個(gè)節(jié)點(diǎn)記錄多次,信息大量冗余,
課程設(shè)計(jì)(論文)
4
如果樹形節(jié)點(diǎn)中保留全部信息,必將造成大量的空間浪費(fèi);只保存作為索
引的少量信息在樹形結(jié)構(gòu)中,節(jié)約了空間。
2.由于結(jié)構(gòu)的精簡,在家譜初始化時(shí)讀入內(nèi)存需要的時(shí)間相應(yīng)減少,節(jié)約
了裝載時(shí)間。
這樣做存在的問題:
每次執(zhí)行修改,添加,刪除,查詢時(shí)都要直接訪問外存來取得或?qū)懭霐?shù)據(jù)。
內(nèi)外存訪問上的巨大時(shí)間差的存在,使得進(jìn)行這些操作相對(duì)來說并不顯得
很高效。
關(guān)于樹形的結(jié)構(gòu):
在樹形結(jié)構(gòu)的選擇上,根據(jù)實(shí)際中多子女的現(xiàn)象選擇一般樹,考慮到家譜中
成員可能存在的不定成員數(shù)問題,拋棄了以數(shù)組為基礎(chǔ)的一般樹方案,決
定用鏈表來實(shí)現(xiàn)。
樹形結(jié)構(gòu)的外存保存。為了提高效率,樹形結(jié)構(gòu)在程序初始化時(shí)由外存文
件一次讀入內(nèi)存,此后不管插入還是修改,刪除都不再對(duì)外存的樹結(jié)構(gòu)保
存文件進(jìn)行操作,只在內(nèi)存中處理,程序退出時(shí)對(duì)外存樹結(jié)構(gòu)文件進(jìn)行一
次更新。也就是說,不管在程序運(yùn)行中中對(duì)家譜結(jié)構(gòu)進(jìn)行多少種,多少次
的操作,外存的樹結(jié)構(gòu)文件始終只會(huì)被程序訪問兩次。
關(guān)于功能的設(shè)計(jì)(以基本要求為準(zhǔn)):
1.插入:用戶按提示輸入資料,在樹形中插入節(jié)點(diǎn),在個(gè)人完整記錄
文件中添加插入人的所有信息并保存。
2.刪除:用戶輸入被刪除人的識(shí)別關(guān)鍵字(即名字),在樹形結(jié)構(gòu)中刪
除此人,在個(gè)人記錄文件中不處理。
3.修改:用戶輸入被刪除任的識(shí)別關(guān)鍵字(即名字),從個(gè)人完整記錄
文件中讀出該人所有信息供用戶進(jìn)行修改,然后寫回。
4.查詢:完成了關(guān)鍵字查找部分和關(guān)系查找部分,讀出個(gè)人全部信息
并顯示。
關(guān)于個(gè)人資料單元:
由于樹形節(jié)點(diǎn)要涉及到大量的邏輯操作,要用到一些運(yùn)算符的重載,個(gè)人
資料在樹形單元定義為class類,而寫入文件的單元存萃是數(shù)據(jù),定義為簡
單的struct類。
定義為struct和class類,使得不管是樹形結(jié)構(gòu)插入刪除還是IO都是對(duì)
整個(gè)結(jié)構(gòu)體進(jìn)行的操作,這樣,如果要往結(jié)構(gòu)體中添加若干個(gè)新信息條目
課程設(shè)計(jì)(論文)
5
或取消一些不必要的信息條目,需要修改的代碼非常之少,方便了以后的
升級(jí)。
2.簡單家譜系統(tǒng)的主要特點(diǎn)及功能
本系統(tǒng)的主要特點(diǎn)是算法簡潔,易于閱讀,用戶交互界面良好。
主要實(shí)現(xiàn)功能:
1.確定指定成員在家族中的輩份
2.輸出指定輩的所有成員
3.在家譜中添加新成員,并追加到文件中
4.輸出指定家庭的所有成員
5.退出本系統(tǒng)
各功能的算法思想:
1.讀出家譜并顯示
存儲(chǔ)結(jié)構(gòu)用棧,按照先顯示雙親,然后顯示其所有孩子的順序顯示所有家
庭成員。
2.確定指定成員在家族中的輩份
用求成員所在的二叉樹中的層數(shù)(按層遍歷二叉樹)來確定,這里采用的是
遞歸算法
3.輸出指定輩的所有成員
此處定義了一個(gè)新的結(jié)構(gòu)體類型(增加存儲(chǔ)節(jié)點(diǎn)所在的層數(shù)),定義如下:
typedefstructcc
{
structcc*child,*next;//next指向同輩份的人物
charName[];
}JPNode;
并用一個(gè)隊(duì)列來比較顯示同輩分的所有成員。
4.在家譜中添加新成員,并追加到文件中
首先,輸入一個(gè)新成員的名字;
然后,輸入其雙親;
之后,再添加到整個(gè)存儲(chǔ)二叉鏈表中。
然后,再將新的存儲(chǔ)結(jié)構(gòu)寫回到文件中。
二叉鏈表的結(jié)點(diǎn)類型為:typedefstructnode
{
課程設(shè)計(jì)(論文)
6
ElemTypedata[10];//存放成員的名字
structnode*child;//其孩子指針
structnode*brother;//其兄弟指針
}BTNode;
5.輸出指定家庭的所有成員
首先,設(shè)一個(gè)棧,并設(shè)一個(gè)標(biāo)記位,先置1;
然后,找到輸入的要待顯示的成員,將標(biāo)記位置0;
再次,顯示其孩子和兄弟,依次下去直到顯示完其所有的親戚。
6.退出本系統(tǒng)。
課程設(shè)計(jì)(論文)
7
三詳細(xì)設(shè)計(jì)
1.查詢?nèi)康募易V成員信息
該部分程序所完成的具體功能是把賈府中所有的成員信息按照輩份依次顯
示出來,首先從賈無名開始,然后下一輩份的賈演、賈源等……最后是賈蓉的
信息。每個(gè)輩份之間都有間隔。
設(shè)計(jì)思想:利用隊(duì)列遍歷所有的結(jié)點(diǎn),在遍歷的同時(shí)依次輸出每個(gè)結(jié)點(diǎn)的
值(即為家庭成員的信息)。
代碼如下:
voidDis_Family(JPNode*p)
{
charname[NAME_length];
JPNode*here=NULL;
printf("請(qǐng)輸入該家庭的首個(gè)成員:");scanf("%s",name);
here=Find_Name(p,name);
if(here==NULL){printf("無該家庭!n");return;}
printf("n");
DispJP(here);
}
2.確定指定成員在家族中的輩份
該部分代碼所完成的具體功能是查詢某一個(gè)家庭成員的信息。首先手動(dòng)輸
入你要查詢的那個(gè)成員的名字,然后利用隊(duì)列依次查找該成員的信息,如果該
家譜中存在這個(gè)成員則輸出該成員的有關(guān)信息;如果家譜中不存在該成員,則
輸出提示信息:家譜中無此人!
設(shè)計(jì)思想:有兩個(gè)函數(shù),一個(gè)函數(shù)(queryElemt)利用隊(duì)列遍歷所有的節(jié)
點(diǎn),在遍歷的同時(shí)即可查找所輸入的成員是否存在該家譜中;另外一個(gè)函數(shù)
(queryElemtoFamily)用于輸入你要查找的成員的輩分和輸出查找的結(jié)果。
代碼如下:
課程設(shè)計(jì)(論文)
8
intbeifen(JPNode*p,charname[])
{
staticintn=1;
staticintlevel=0;
if(p==NULL)returnlevel;
if(Equal(p->Name,name)==1)return(level=n);
n++;beifen(p->child,name);
n--;beifen(p->next,name);//向右查詢n不必加(先加后減)!
returnlevel;
}
voidBei_Fen(JPNode*p)
{
charname[NAME_length];
intn=0;
printf("請(qǐng)輸入要查明輩分的人的姓名:");scanf("%s",name);
n=beifen(p,name);
if(n==0)printf("該家族中無此人!n");
elprintf("n%s是%s家族中的第%d輩n",name,p->Name,n);
}
//////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////
/*輸出指定輩的所有成員*/
voidchabei(JPNode*p,intbei)
{
staticintn=1;
staticinttag=0;
if(p==NULL)return;
if(bei==n){tag=1;printf("%s",p->Name);}
n++;chabei(p->child,bei);
課程設(shè)計(jì)(論文)
9
n--;chabei(p->next,bei);//向右查詢n不必加(先加后減)!
if(tag==0)printf("該家族中還沒有這一輩呢....n");
}
voidDisp_Pei(JPNode*p)
{
intbei;
printf("n你想要查看那一輩的成員:");
scanf("%d",&bei);
printf("n....該家族中輩分為%d的成員有....nn",bei);
chabei(p,bei);
printf("n");
}
3.在家譜中添加新成員,并追加到文件中
該部分程序所完成的具體功能是:輸入你要添加人的名字,比如吳長,他
會(huì)被添加到文件中。
設(shè)計(jì)思想:首先確定他的父母,然后把他添加到他的父母的根節(jié)點(diǎn)之下。
代碼如下:
intEqual(charconst*p,charconstq[])//判斷兩個(gè)字符串是否相等
{
while(*p++==*q++)if(*p=='0'&&*q=='0')return(1);
return(0);
}
JPNode*Find_Name(JPNode*s,char*parent)//定位家譜中的成員。返回其
指針(地址)
{
staticJPNode*here=NULL;
if(s==NULL)returnhere;
if(Equal(s->Name,parent)==1)return(here=s);
課程設(shè)計(jì)(論文)
10
here=Find_Name(s->child,parent);
here=Find_Name(s->next,parent);
returnhere;
}
voidPrint_FILE(JPNode*p,FILE*fp)
{
staticintlevel=0;
inti;
if(p!=NULL)
{
for(i=0;i
fprintf(fp,"%sn",p->Name);
}
elreturn;
level++;
Print_FILE(p->child,fp);
level--;
Print_FILE(p->next,fp);
}
voidADD_number(JPNode*p)//在家譜中添加新成員,并寫入文件
{
charparent[NAME_length],name[NAME_length];
FILE*fp=NULL;
JPNode*here=NULL;
JPNode*s=(JPNode*)malloc(2*sizeof(void*)+strlen(name)+1);
s->next=s->child=NULL;
printf("請(qǐng)輸入要添加的新成員的雙親姓名:");scanf("%s",parent);
printf("請(qǐng)輸入要添加的新成員的姓名:");scanf("%s",name);
strcpy(s->Name,name);
課程設(shè)計(jì)(論文)
11
here=Find_Name(p,parent);
if(here->child==NULL)here->child=s;
el
{
here=here->child;
while(here->next!=NULL)here=here->next;
here->next=s;
}
fp=fopen("jiapu_","w");
Print_FILE(p,fp);
fclo(fp);
}
課程設(shè)計(jì)(論文)
12
四程序的調(diào)試與運(yùn)行結(jié)果說明
1.實(shí)驗(yàn)結(jié)果截圖:
2.調(diào)試時(shí)遇到的問題
(1)當(dāng)選擇功能3(添加新成員),添加完成員后,寫回文件時(shí)出現(xiàn)了錯(cuò)誤,
原本添加的為其中一個(gè)結(jié)點(diǎn)的孩子,結(jié)果寫回文件時(shí)卻成了該結(jié)點(diǎn)的孫子,也就
是本是要添加為此結(jié)點(diǎn)的孩子的兄弟,結(jié)果卻成了其孩子的孩子。最后經(jīng)過單步
跟蹤發(fā)現(xiàn)寫入文件的函數(shù)編寫錯(cuò)誤,缺少判斷條件,經(jīng)過修改后,此問題得到了
課程設(shè)計(jì)(論文)
13
解決。
(2)當(dāng)選擇功能0(顯示此家譜),沒有按照事先存儲(chǔ)在txt中的文件顯示,
通過認(rèn)真檢查程序中顯示成員的函數(shù)(按層遍歷)、不斷調(diào)試,發(fā)現(xiàn)并不是該顯
示函數(shù)的錯(cuò)誤,因?yàn)樵诠δ?(輸出指定家庭的所有成員)中,也是通過調(diào)用該
函數(shù)實(shí)現(xiàn)輸出功能,于是,檢查txt文件中事先存儲(chǔ)的家譜成員,發(fā)現(xiàn)是由于“(”
與“)”沒有匹配好,導(dǎo)致沒有按照預(yù)期想法創(chuàng)建二叉樹造成的錯(cuò)誤,通過修改
txt文件,使得錯(cuò)誤得以解決。
五課程設(shè)計(jì)總結(jié)
本組的課程任務(wù)為簡易家譜,在組長的帶領(lǐng)下,經(jīng)過我們共同的努力,本
程序主要任務(wù)已基本完成。另外本程序功能完善,具有良好的交互性,可以滿
足用戶多種需求。美中不足的是本系統(tǒng)沒有采用之前我所設(shè)想的遞歸,我們這
課程設(shè)計(jì)(論文)
14
次改用隊(duì)列來建樹、查找等,這樣代碼少有一定的冗余,如果時(shí)間充分,我們
會(huì)更加精進(jìn),爭取采用代碼量相對(duì)較少的遞歸算法,另外更加完善一些功能,
包括增加日志功能,給不同級(jí)別的人員設(shè)置管理權(quán)限,比如說家譜管理員在獲
得本族長的同意下修改某個(gè)成員的信息,而其他成員只具備瀏覽的功能。
在本程序簡易家譜的創(chuàng)作過程中,我們組員各抒己見,意見很不一致,包
括是采用遞歸算法,還是采用隊(duì)列;數(shù)據(jù)成員的結(jié)構(gòu)如何定義,甚至包括成員
的名字,大家的意見都不統(tǒng)一。但是在探討的過程中,我們也理解自己思維的
不足,也見識(shí)了另外不同的編程思想,這也讓我體會(huì)到了交流的魅力。只有我
們大家坦誠布公的把自己想法說出來,然后我們?cè)诶硇缘姆治鏊惴ǖ膬?yōu)劣與可
行性,這樣就能結(jié)合大家共同的智慧,組織大家共同的力量,為共同的目標(biāo)努
力奮斗。次大作業(yè)的推薦學(xué)時(shí)是20個(gè)學(xué)時(shí),但回想起來,光這篇報(bào)告就寫了有
三四個(gè)學(xué)時(shí),由于我本身編程能力不強(qiáng),構(gòu)思,寫代碼,修改,調(diào)試的時(shí)間加
起來絕對(duì)是有余了。雖然付出不少,但在前期的設(shè)計(jì)組織中,中期的代碼編寫
和后期的修改調(diào)試中都學(xué)到了不少。
起初我的家譜中數(shù)據(jù)并不是以結(jié)構(gòu)的形式打包,讀入,寫出操作的時(shí)候代
碼異常繁瑣,這是恰好看到一本編程書上有用結(jié)構(gòu)輸入輸出的范例,深深感到
結(jié)構(gòu)化確實(shí)是方便多了,而且讀寫不容易出錯(cuò)。當(dāng)時(shí)我的代碼本已經(jīng)寫了有一
大半,思慮再三,還是決定進(jìn)行大換血,家譜數(shù)據(jù)的改變讓程序來了個(gè)大換血,
提高了效率的同時(shí),代碼幾乎變了一多半。我想,當(dāng)時(shí)唯一不變的就只有對(duì)整
個(gè)程序越來越清醒地認(rèn)識(shí)和對(duì)將要完成的代碼的更準(zhǔn)確地把握。
代碼完成之后,一編譯,至少有五六十個(gè)錯(cuò)誤提示,而且最末debug一行
欄的最后一行提示因?yàn)橄惹暗腻e(cuò)誤而中斷編譯,有的是指針指向錯(cuò)誤,有的是
忘了分號(hào),括號(hào),更多的是一些賦值錯(cuò)誤,前面的錯(cuò)誤都好改,賦值錯(cuò)誤就比
較麻煩了,因?yàn)橐褂觅x值的地方太多,逐行改代碼雖然也可以,但實(shí)在是一
個(gè)巨大工程。所謂巧招必是險(xiǎn)招——至少對(duì)我是這樣——說來慚愧,我只有嘗
試著寫以前從未是過的運(yùn)算符重載函數(shù),為此專門翻找出了大一的C++教材,
溫習(xí)了一番運(yùn)算符重載才戰(zhàn)戰(zhàn)兢兢地搞定了賦值問題。
試運(yùn)行時(shí)出現(xiàn)了更多的問題,而且更具有隱蔽性,幾次為了一個(gè)邏輯錯(cuò)誤
而來回反復(fù)地翻看代碼,嘿嘿,再加上網(wǎng)上有代碼的傳說,讓人有想直接放棄
的沖動(dòng),但一想到寫代碼的辛苦,覺得放棄了實(shí)在可惜。那幾天吃飯,睡覺,
走路,看電視,隨時(shí)隨地,都記掛著那幾處錯(cuò)誤,腦子都會(huì)浮現(xiàn)出代碼的影子,
不自覺地開始找錯(cuò)誤。哎~那種感覺!~不知道是充實(shí)還是急迫地?zé)溃詈蠼K
于找到了,根本來不急高興,只有松了一口氣和一陣的疲憊。
現(xiàn)在程序終于完成了,心里的石頭也下了地。至于成績,不想了~~
課程設(shè)計(jì)(論文)
15
另外,通過本次課程設(shè)計(jì),我覺得自己最大的收獲就是:
(1)學(xué)會(huì)了怎樣將課堂所學(xué)知識(shí)運(yùn)用到較為實(shí)際的應(yīng)用中來
由于對(duì)二叉鏈表的存儲(chǔ)比較感興趣,我選做的是家譜,開始覺得無從下手,但是
經(jīng)過仔細(xì)分析后,漸漸找到一點(diǎn)思路(首先創(chuàng)建,然后分別實(shí)現(xiàn)各個(gè)功能,最后
利用菜單實(shí)現(xiàn)選擇功能并輸出結(jié)果)。
(2)鍛煉提出問題、解決問題和自學(xué)的能力
家譜的實(shí)現(xiàn)要求讀、寫文件,于是“如何將文件從文檔中讀出”,“怎么寫入文
件”都是要滿足要求必須解決的問題。為此,我查找了很多資料,最后自學(xué)、解
決這一問題
(3)增加了對(duì)編程的熱愛和興趣
本次編寫家譜程序的過程中,我體驗(yàn)到了編程的酸甜苦辣:開始,由于即將運(yùn)用
所學(xué)知識(shí)設(shè)計(jì)實(shí)際問題而激動(dòng)興奮;后來編寫程序過程中,在想不出算法如何實(shí)
現(xiàn)或者追求空間、時(shí)間上高效率的算法時(shí)會(huì)比較糾結(jié);以及遇到BUG時(shí),追蹤數(shù)
據(jù)的痛苦;當(dāng)然,還有解決問題后的激動(dòng)與自豪。所有這些都增強(qiáng)了我對(duì)編程的
熱愛、提高了我對(duì)計(jì)算機(jī)專業(yè)的興趣。
課程設(shè)計(jì)(論文)
16
附錄一:程序源代碼
#include
#include
#include
#include
#defineNAME_length50//名字最大長度
#defineLINE_length100//文本行最大長度
typedefstructcc
{
structcc*child,*next;//next指向同輩份的人物
charName[];
}JPNode;
voidclear(charp[],intn)//清空字符數(shù)組p
{
while(n-->0)
*p++='0';
}
staticJPNode*last=NULL;
staticintlast_level=0;
voidAddJP(JPNode**head,charconstname[],intlevel)
{
JPNode**s=head,*r=NULL;
JPNode*p=(JPNode*)malloc(2*sizeof(void*)+strlen(name)+1);
p->child=p->next=NULL;
strcpy(p->Name,name);
if(*s==NULL)
{
課程設(shè)計(jì)(論文)
17
*s=p;
last=p;
return;
}
if(level-last_level==1){last->child=p;last=
p;last_level=level;return;}
if((level==last_level)&&(*s!=NULL)){last->next=p;last=
p;last_level=level;return;}
r=*s;//r指向家譜樹
last_level=level;
while(level-->0)//找到相同的輩分
{
while(r->next!=NULL)r=r->next;
r=r->child;
}//以兄弟連接
while(r->next!=NULL)r=r->next;
r->next=p;
last=p;
}
voidCreatJP(JPNode**head)
{
charname[NAME_length]="",line[LINE_length]="";
char*p=NULL;
intlevel=0,i=0;//輩分,以制表符個(gè)
數(shù)表示
FILE*fp=NULL;
fp=fopen("jiapu_","r");
if(fp==NULL){printf("openerror!n");exit(1);}
while(level=0,i=0,fgets(line,LINE_length,fp)!=NULL)
課程設(shè)計(jì)(論文)
18
{
p=line;
while(*p++=='t')level++;//計(jì)算輩分,計(jì)算完后p指向名
字開始處
while(line[i++]!='n')
;
line[i-1]='0';//讀入的換行符用字符串結(jié)束標(biāo)識(shí)
符替換
strcpy(name,p-1);
AddJP(head,name,level);
clear(name,NAME_length);clear(line,LINE_length);
}
fclo(fp);
}
voidDispJP(JPNode*p)//從p指向的結(jié)點(diǎn)顯示該家族
{
staticintlevel=0;
inti;
if(p!=NULL)
{
for(i=0;i
printf("%sn",p->Name);
}
elreturn;
level++;
DispJP(p->child);
level--;
DispJP(p->next);
}
課程設(shè)計(jì)(論文)
19
////////////////////////////////////////////////////////////////////
///////
/*在家譜中添加新成員,并追加到文件中*/
intEqual(charconst*p,charconstq[])//判斷兩個(gè)字符串是否相等
{
while(*p++==*q++)if(*p=='0'&&*q=='0')return(1);
return(0);
}
JPNode*Find_Name(JPNode*s,char*parent)//定位家譜中的成員。返回其
指針(地址)
{
staticJPNode*here=NULL;
if(s==NULL)returnhere;
if(Equal(s->Name,parent)==1)return(here=s);
here=Find_Name(s->child,parent);
here=Find_Name(s->next,parent);
returnhere;
}
voidPrint_FILE(JPNode*p,FILE*fp)
{
staticintlevel=0;
inti;
if(p!=NULL)
{
for(i=0;i
fprintf(fp,"%sn",p->Name);
}
elreturn;
level++;
課程設(shè)計(jì)(論文)
20
Print_FILE(p->child,fp);
level--;
Print_FILE(p->next,fp);
}
voidADD_number(JPNode*p)//在家譜中添加新成員,并寫入文件
{
charparent[NAME_length],name[NAME_length];
FILE*fp=NULL;
JPNode*here=NULL;
JPNode*s=(JPNode*)malloc(2*sizeof(void*)+strlen(name)+1);
s->next=s->child=NULL;
printf("請(qǐng)輸入要添加的新成員的雙親姓名:");scanf("%s",parent);
printf("請(qǐng)輸入要添加的新成員的姓名:");scanf("%s",name);
strcpy(s->Name,name);
here=Find_Name(p,parent);
if(here->child==NULL)here->child=s;
el
{
here=here->child;
while(here->next!=NULL)here=here->next;
here->next=s;
}
fp=fopen("jiapu_","w");
Print_FILE(p,fp);
fclo(fp);
}
//////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////
/*輸出指定家庭的所有成員*/
課程設(shè)計(jì)(論文)
21
voidDis_Family(JPNode*p)
{
charname[NAME_length];
JPNode*here=NULL;
printf("請(qǐng)輸入該家庭的首個(gè)成員:");scanf("%s",name);
here=Find_Name(p,name);
if(here==NULL){printf("無該家庭!n");return;}
printf("n");
DispJP(here);
}
///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
/*確定指定成員在家族中的輩份*/
intbeifen(JPNode*p,charname[])
{
staticintn=1;
staticintlevel=0;
if(p==NULL)returnlevel;
if(Equal(p->Name,name)==1)return(level=n);
n++;beifen(p->child,name);
n--;beifen(p->next,name);//向右查詢n不必加(先加后減)!
returnlevel;
}
voidBei_Fen(JPNode*p)
{
charname[NAME_length];
intn=0;
printf("請(qǐng)輸入要查明輩分的人的姓名:");scanf("%s",name);
n=beifen(p,name);
課程設(shè)計(jì)(論文)
22
if(n==0)printf("該家族中無此人!n");
elprintf("n%s是%s家族中的第%d輩n",name,p->Name,n);
}
//////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////
/*輸出指定輩的所有成員*/
voidchabei(JPNode*p,intbei)
{
staticintn=1;
staticinttag=0;
if(p==NULL)return;
if(bei==n){tag=1;printf("%s",p->Name);}
n++;chabei(p->child,bei);
n--;chabei(p->next,bei);//向右查詢n不必加(先加后減)!
if(tag==0)printf("該家族中還沒有這一輩呢....n");
}
voidDisp_Pei(JPNode*p)
{
intbei;
printf("n你想要查看那一輩的成員:");
scanf("%d",&bei);
printf("n....該家族中輩分為%d的成員有....nn",bei);
chabei(p,bei);
printf("n");
}
/////////////////////////////////////////////////////////////////
voidmenu(void);
intmain(void)
課程設(shè)計(jì)(論文)
23
{
JPNode*JP=NULL;//家譜無結(jié)點(diǎn)
charch='1',cc;
CreatJP(&JP);
while(ch)
{
system("cls");
menu();
printf("n...請(qǐng)選擇:");
scanf("%c",&ch);
//ch=getchar();
switch(ch)
{
ca'1':ADD_number(JP);break;
ca'2':Dis_Family(JP);break;
ca'3':Bei_Fen(JP);break;
ca'4':Disp_Pei(JP);break;
default:ch='0';break;
}
getche();while((cc=getchar())!='n');
}
return0;
}
voidmenu(void)
{
printf("n****************家譜操作菜單****************n");
printf("
*(1)在家譜中添加新成員,并追加到文件中。*n
*(2)輸出指定家庭的所有成員。*n
課程設(shè)計(jì)(論文)
24
*(3)確定指定成員在家族中的輩份(第幾代)。*n
*(4)輸出指定輩的所有成員。*n
*(0)退出操作!*n
********************************************n");
}
課程設(shè)計(jì)(論文)
25
附錄二:參考文獻(xiàn)
如:
[1]譚浩強(qiáng),C程序設(shè)計(jì)題解與上機(jī)指導(dǎo)(第二版),北京,清華大學(xué)出版社,2000年9月。
[2]嚴(yán)蔚敏,吳偉民,數(shù)據(jù)結(jié)構(gòu),北京,清華大學(xué)出版社,2004年6月。
[3]殷人昆,陶永雷,謝若陽等,數(shù)據(jù)結(jié)構(gòu),北京,清華大學(xué)出版社,2005年3月。
[4]沈晴霓,聶青,蘇京霞,現(xiàn)代程序設(shè)計(jì)──C++與數(shù)據(jù)結(jié)構(gòu)面向?qū)ο蟮姆椒ㄅc實(shí)現(xiàn),
北京,北京理工大學(xué)出版社,2002年3月。
[5]朱戰(zhàn)立,張選平,數(shù)據(jù)結(jié)構(gòu)學(xué)習(xí)指導(dǎo)與典型題解,西安,西安交通大學(xué)出版社,2002
年7月。
[6]羅文劼,王苗,石強(qiáng),數(shù)據(jù)結(jié)構(gòu)習(xí)題解答與實(shí)驗(yàn)指導(dǎo),北京,中國鐵道出版社,2004
年11月。
課程設(shè)計(jì)(論文)
26
簡易家譜課程設(shè)計(jì)成績?cè)u(píng)定表
1、課程設(shè)計(jì)答辯或質(zhì)疑記錄
1)
2)
3)
2、答辯情況
a)未能完全理解題目,答辯情況較差□
b)部分理解題目,答辯情況較差□
c)理解題目較清楚,問題回答基本正確□
d)理解題目透徹,問題回答流利□
3、課程設(shè)計(jì)報(bào)告
a)內(nèi)容:不完整□完整□詳細(xì)□
b)方案設(shè)計(jì):較差□合理□非常合理□
c)實(shí)現(xiàn):未實(shí)現(xiàn)□部分實(shí)現(xiàn)□全部實(shí)現(xiàn)□
d)文檔格式:不規(guī)范□基本規(guī)范□規(guī)范□
考勤成績:,占總成績比例10%
答辯成績:,占總成績比例30%
課程設(shè)計(jì)論文成績:,占總成績比例60%
課程設(shè)計(jì)總成績:
指導(dǎo)教師簽字:
年月日
課程設(shè)計(jì)(論文)
27
本文發(fā)布于:2023-03-08 00:26:32,感謝您對(duì)本站的認(rèn)可!
本文鏈接:http://m.newhan.cn/zhishi/a/16782063925831.html
版權(quán)聲明:本站內(nèi)容均來自互聯(lián)網(wǎng),僅供演示用,請(qǐng)勿用于商業(yè)和其他非法用途。如果侵犯了您的權(quán)益請(qǐng)與我們聯(lián)系,我們將在24小時(shí)內(nèi)刪除。
本文word下載地址:家譜樹.doc
本文 PDF 下載地址:家譜樹.pdf
| 留言與評(píng)論(共有 0 條評(píng)論) |