洛 阳 理 工 学 院
课 程 设 计 报 告
数据结构课程设计 课程名称 ___________________________________ 家谱管理系统 设计题目 ___________________________________ 计算机科学与技术 专 业 ___________________________________ 班 级 ___________________________________ B150405 学 号 ___________________________________ 宋士龙 姓 名 ___________________________________ 2016年12月30日 完成日期 ___________________________________ 课 程 设 计 任 务 书 设计题目:家谱管理系统 设计内容与要求: 【问题描述】:实现具有下列功能的家谱管理系统 1). 输入文件以存放最初家谱中各成员的信息,成员的信息中均应包含以下内容: 姓名、出生日期、婚否、地址、健在否、死亡日期(若其已死亡),也可附加其它信息、但不是必需的。 2). 实现数据的存盘和读盘。 3). 显示家谱。 4). 按照出生日期查询成员名单。
5). 按照姓名查询,输出成员信息(包括其本人、父亲、孩子的信息)。 6). 修改某成员信息。 【基本要求】:
界面要求:有合理的提示,每个功能可以设立菜单,根据提示,可以完成相关的功能要求。
存储结构:学生自己根据系统功能要求自己设计,但是要求相关数据要存储在数据文件中。
测试数据:要求使用1、全部合法数据;2、局部非法数据。进行程序测试,以保证
精心整理
精心整理
程序的稳定。
测试数据及测试结果请在上交的资料中写明。
指导教师:_______________ 年 月 日
课 程 设 计 评 语
成绩:
精心整理
指导教师:_______________ 年 月 日
一、 算法思想
本程序是一个管理家谱的系统,通过这个系统可以对家族成员进行创建、显示、查找
、修改、以及保存家谱和读取家谱功能。该系统分为以下几个模块,分别是:创建家谱,显示家谱、按姓名和生日查找家庭成员、修改家谱、存盘、读盘以及退出系统。本程序用到的存储形式为多叉树,因为家谱中每个人既有父母又有孩子,而且孩子的个数并不确定,所以用多叉树来存储最为合适。用多叉树来存储,就用用到多叉树的递归创建及递归遍历。因为是多叉树,所以遍历时用广度优先搜索合适。本函数最主要的思想就是递归调用,每个子函数中都会用到递归。定义结构体时给定指针数组的最大容量,来规定家谱中最多可以存多少人。定义一个家族树的指针变量用来当每个子函数的参数,从而将其返回到主函数中。 以下时算法思想流程图: 精心整理
家谱管理创建家显示家查找成修改家读写家按照按照修修修改改改存读退出系统
二、 模块划分 1. 2. 3. 4. 5. 6. 7. int main():主函数 void CreatTree(TreeNode *Tree):创建家族树 void OutPutAll(TreeNode *Tree):显示家谱 void Menue(TreeNode *Tree):主菜单 void SubMenue1(TreeNode * Tree):副菜单(修改选项菜单) void Change(TreeNode * Tree):修改家谱 TreeNode * SearchTree(TreeNode *Tree,char name[],int length):按照姓名查找家谱成员 8. TreeNode * SearchTree1(TreeNode *Tree,char birth[],int length):按照生日查找家谱成员 9. void OutPutMessage(TreeNode * Tree,char name[],int length):输出按姓名查找到的家谱成员 10. void OutPutMessage1(TreeNode * Tree,char birth[],int length):输出按生日查找
到的家谱成员
11. void SaveFamily(TreeNode *root):保存家谱 12. void ReadFamily(TreeNode **root):读取家谱
三、 数据结构
typedef struct TreeNode 精心整理
{
int ChildNum; //记录这个人拥有几个儿女
char Name[20];//记录这个人的姓名 char birthday[20];//生日
int marriage;//婚否(1表示结婚,0表示没结婚) int death;//生死(1表示活着,0表示过世) char Kind;//标示节点的种类有女G男B char address[100];//住址 char livemassage[50];//死亡日期(如果其已经死亡) struct TreeNode *NextNode[20]; //记录这个人的儿女 struct TreeNode *Parent; //记录这个节点的父节点 }TreeNode,*tree; 四、 测试 第一组数据为: 爷爷,奶奶,爸爸,妈妈,我,二叔,二婶,姐姐,三叔,三婶,弟弟一共三代11个人。 其中爷爷是根节点,奶奶为爷爷的配偶,同时也是爷爷的第一个后继节点。爸爸,二叔,三叔为爷爷的子女。爸爸的配偶是妈妈,爸爸的子女是我。二叔的配偶是二婶,子女是姐姐。三叔的的配偶是三婶,三叔的的子女是弟弟。 进入程序之后,首先进行创建家谱,然后进行存盘,之后进行修改和查询等步骤。退出程序在进入程序时,进行读盘。之后在进行其他操作,程序完成之后退出即可。
精心整理
爷爷 奶奶 爸爸 妈妈 二叔 二婶 三叔 三婶 我 姐姐 弟弟
图1 家族树 第一组数据测试截图为: 图2 显示家谱 图3 按照姓名查找家族成员 图4 存盘 第二组数据为: 王刘王李王张王王
图4 王家家族树
精心整理
第二组数据测试截屏为:
图5 修改家族成员的信息 图6 修改某个人的具体信息 图7 按照生日查找某人
图8 读盘
五、 源程序 #include #define TipForReadFilePosition printf(\"\\文件名及其路径(eg: /home/xiong/example.txt): \") #endif #define maxFileNameLen 50 //保存的文件名的最大长度 精心整理 int FLAG=0; int a=1; typedef struct TreeNode { int ChildNum; //记录这个人拥有几个儿女 char Name[20];//记录这个人的姓名 char birthday[20];//生日 int marriage;//婚否(1表示结婚,0表示没结婚) int death;//生死(1表示活着,0表示过世) char Kind;//标示节点的种类有女G男B char address[100];//住址 char livemassage[50];//死亡日期(如果其已经死亡) struct TreeNode *NextNode[20]; //记录这个人的儿女 struct TreeNode *Parent; //记录这个节点的父节点 }TreeNode,*tree; void CreatTree(TreeNode *Tree); void OutPutAll(TreeNode *Tree); void Menue(TreeNode *Tree); void SubMenue1(TreeNode * Tree); void SubMenue2(TreeNode *Tree); void Change(TreeNode * Tree); void AddNew(TreeNode * Tree); 精心整理 TreeNode * SearchTree(TreeNode *Tree,char name[],int length); TreeNode * SearchTree1(TreeNode *Tree,char birth[],int length) ; void OutPutMessage(TreeNode * Tree,char name[],int length); void OutPutMessage1(TreeNode * Tree,char birth[],int length); void SaveFamily(TreeNode *root); void ReadFamily(TreeNode **root); int main()//主函数 { TreeNode *Tree;//TreeNode **Tree1; //Tree1=&(*Tree); Tree=(TreeNode *)malloc(sizeof(TreeNode)); Tree->Parent =NULL; strcpy(Tree->Name,\"0\"); } void Menue(TreeNode *Tree)//输出主菜单 { /*TreeNode **Tree1; Tree1=&Tree;*/ char c; char name[20]; Menue(Tree); return 0; 精心整理 char birth[20]; while(1) { system(\"cls\"); printf(\"\\"); printf(\"\\n\\n\\**********欢 迎 使 用 家 族 管 理 系 统**********\\n\\n\"); printf(\"\\n\\ A:输入家谱信息建立树 \"); printf(\"\\n\\ B:输出整个家谱信息 printf(\"\\n\\ C:按出生日期查找某人 printf(\"\\n\\ D:按姓名查找某人 \"); printf(\"\\n\\ E:修改某个人的信息 \"); printf(\"\\n\\ F:存盘 \"); printf(\"\\n\\ G:读盘 \"); printf(\"\\n\\ H:退出整个程序 \\n\\"); c=getchar(); switch(c) { 精心整理 \"); \"); case 'A': TreeNode * NewNode; NewNode=(TreeNode *)malloc(sizeof(TreeNode)); printf(\"\\n\请输入姓名:\"); scanf(\"%s\ printf(\"\\n\请输入性别女G男B:\"); getchar(); scanf(\"%c\Tree->Parent=NewNode; Tree->Parent=NULL;// CreatTree(Tree); // printf(\"\\n\--------------家谱图已经建立成功---------------\\n\\n\"); printf(\"\\n\\n\--------------请按Enter键继续操作--------------\"); getchar(); break; case 'B': if(strcmp(Tree->Name,\"0\")==0) { printf(\"\\n\家谱图的多叉树尚未建立请先建立树\\n\"); getchar(); break; } 精心整理 printf(\"\\n\\n\-----*----*----*----*----*----*----*----*----*----*----\\n\\"); getchar(); break; printf(\"\\n\\n\整个家谱的主要信息如下:\"); OutPutAll(Tree); getchar(); break; case 'C': if(strcmp(Tree->birthday,\"0\")==0) { printf(\"\\n\家谱图的多叉树尚未建立请先建立树\\n\"); getchar(); break; } printf(\"\\n\请输入你要查找的出生日期:\"); scanf(\"%s\ OutPutMessage1(SearchTree1(Tree,birth,20),birth,20); case 'D': if(strcmp(Tree->Name,\"0\")==0) { printf(\"\\n\家谱图的多叉树尚未建立请先建立树\\n\"); 精心整理 printf(\"\\n\\n\-----*----*----*----*----*----*----*----*----*----*----\\n\\"); getchar(); break; getchar(); break; } printf(\"\\n\请输入你要查找的人的姓名:\\n\\"); scanf(\"%s\ OutPutMessage(SearchTree(Tree,name,20),name,20); case 'E': if(strcmp(Tree->Name,\"0\")==0) { printf(\"\\n\家谱图的多叉树尚未建立请先建立树\\n\"); getchar(); break; } Change(Tree); getchar(); break; case 'F': if(strcmp(Tree->Name,\"0\")==0) 精心整理 { } SaveFamily(Tree); getchar(); break; printf(\"\\n\家谱图的多叉树尚未建立请先建立树\\n\"); getchar(); break; case 'G': /*if(strcmp(Tree->Name,\"0\")==0) { printf(\"\\n\家谱图的多叉树尚未建立请先建立树\\n\"); getchar(); break; }*/ ReadFamily(&Tree); getchar(); break; case 'H': printf(\"\\n\\n\-----------------本次服务到此结束 ------------------\"); 精心整理 printf(\"\\n\------------------欢迎下次使用 ---------------------\"); printf(\"\\n\----------------------谢谢 -------------------------\\n\\n\"); break; case '\\n': break; default: printf(\"\\n\\n\--------对不起!你的选择不在服务范围之内!-----------\"); printf(\"\\n\-----------请您再次选择所需的服务项!---------------\"); printf(\"\\n\------------------谢谢------------------------\\n\\"); getchar(); break; } } void CreatTree(TreeNode *Node) //创建树 精心整理 } if (c=='H'||c=='f') break; getchar(); { int i; TreeNode *NewNode; NewNode=(TreeNode *)malloc(sizeof(TreeNode)); Node->NextNode[0]=NewNode; Node->NextNode[0]=NULL; printf(\"\\n\请输入出生日期:\"); scanf(\"%s\ printf(\"\\n\请输入家庭住址:\");getchar(); scanf(\"%s\ printf(\"\\n\请输入是否建在(1-是或0-否):\"); scanf(\"%d\ if(Node->death==0) { printf(\"\\n\请输入去世日期:\"); scanf(\"%s\ } else if(Node->death=='1') printf(\"\\n\仍然建在\"); printf(\"\\n\请输入%s的配偶的姓名(输入0代表没结 婚):\ scanf(\"%s\ 精心整理 if(strcmp(NewNode->Name,\"0\")!=0) {printf(\"\请输入配偶的出生日期:\"); scanf(\"%s\ printf(\"\\n\请输入家庭住址:\");getchar(); scanf(\"%s\printf(\"\\n\请输入是否建在(1-是或0-否):\"); scanf(\"%d\ if(NewNode->death==0) { printf(\"\\n\请输入去世日期:\"); scanf(\"%s\ } else if(NewNode->death=='1') printf(\"\\n\仍然建在\");} printf(\"\\n\请输入%s的子女的数目(当子女输入0时便停止输入 该成员有关信息):\ scanf(\"%d\ if((Node->ChildNum)==0&&strcmp(NewNode->Name,\"0\")==0) return ; if(Node->Kind=='G'||Node->Kind=='g') NewNode->Kind='B'; else 精心整理 NewNode->Kind='G'; NewNode->ChildNum=0; NewNode->NextNode[0]=NULL; Node->NextNode[0]=NewNode; Node->NextNode[0]->Parent=Node;//孩子的父母 for(i=1;i<=Node->ChildNum;i++) { NewNode=(TreeNode *)malloc(sizeof(TreeNode));a++; printf(\"\\n\请输入%s的第%d子女的名字:\ scanf(\"%s\ printf(\"\\n\请输入%s的第%d子女的性别女G男B:\ } void OutPutAll(TreeNode *Tree) { 精心整理 } getchar(); scanf(\"%c\NewNode->ChildNum=-1; NewNode->Parent=Node; Node->NextNode[i]=NewNode; CreatTree(Node->NextNode[i]); //从子女的数目开始 \"); printf(\"\\n\姓名:%s 出生日期:%s 家庭住址:%s 性int i, flag=0; printf(\"\\n\---****---***---***---***---***---***---***---***---***--- 别: %c\ if (Tree->Kind=='G'||Tree->Kind=='g') { } else printf(\"男\"); flag=1; printf(\"女\"); printf(\"\是否健在(1-健在,0-去世):\"); if(Tree->death==1) printf(\"1\"); else if(Tree->death==0) printf(\"0\"); if (!(Tree->NextNode[0])) { printf(\"\\n\至今没有配偶和子女\\n\"); return; } if(flag==1) printf(\"\\n\丈夫 姓名:%s\ 精心整理 性别%c\NextNode[i]->address,Tree->NextNode[i]->Kind); if else printf(\"\\n\妻子 姓名:%s\ printf(\"\是否健在(1-健在,0-去世):\"); if(Tree->death==1) printf(\"1\"); else if(Tree->death==0) printf(\"0\"); for(i=1;i<=Tree->ChildNum;i++) { printf(\"\\n\第%d个子女的姓名:%s 出生日期:%s 家庭住址:%s (Tree->NextNode[i]->Kind=='G'||Tree->NextNode[i]->Kind=='g') printf(\"女\"); else printf(\"男\"); printf(\"\是否健在(1-健在,0-去世):\"); if(Tree->death==1) printf(\"1\"); else if(Tree->death==0) printf(\"0\"); } printf(\"\\n\\"); for(i=1;i<=Tree->ChildNum;i++) 精心整理 } TreeNode * SearchTree(TreeNode *Tree,char name[],int length) { int i; TreeNode *NewNode; if(strcmp(Tree->Name,name)==0) { if(length==0) { } OutPutAll(Tree->NextNode[i]); FLAG=1; } if(Tree->NextNode[0]==NULL) return NULL; else FLAG=0; return Tree; for(i=0;i<=Tree->ChildNum;i++) { if (i==0) NewNode=SearchTree(Tree->NextNode[i],name,0); 精心整理 else } void OutPutMessage(TreeNode * Tree,char name[],int length) { int flag=0,i; TreeNode *NewNode; } return NULL; NewNode=SearchTree(Tree->NextNode[i],name,20); if (NewNode!=NULL) return NewNode; printf(\"\\n\\n\-----*----*----*----*----*----*----*----*----*----*----\"); if(Tree==NULL) { printf(\"\\n\\n\****该家谱图中没有%s这个人的信息请确认是否输入错误*****\\n\ return; } printf(\"\\n\\n\您所要找的人已经找到信息如下所示:\"); printf(\"\\n\\n\姓名:%s出生日期:%s 家庭住址:%s 性 别:%c\ if (Tree->Kind=='G'||Tree->Kind=='g') 精心整理 { flag=1; //标记他(她)的性别 printf(\"女\"); } else printf(\"男\"); printf(\"\是否健在(1-健在,0-去世):\"); if(Tree->death==1) printf(\"1\"); else if(Tree->death==0) printf(\"0\"); NewNode=Tree->Parent; if (FLAG==1) { if(flag==1) { printf(\"\\n\\n\她是嫁入此家族的所以亲生父母信息不在家谱内包括\"); printf(\"\\n\丈夫 姓名:%s\ } else { printf(\"\\n\\n\他是入赘此家族的所以亲生父母信息不在家 谱内包括\"); 精心整理 printf(\"\\n\妻子姓名:%s\ } if ((NewNode->ChildNum)>0) //判断他(她)是否有孩子 { printf(\"\\n\的孩子的信息如下:\"); //输出他(她)的孩子的信息 for(i=1;i<=NewNode->ChildNum;i++) { printf(\"\\n\姓名:%s 性别:\if (NewNode->NextNode[i]->Kind=='G'||NewNode->Kind=='g') printf(\"女\"); else printf(\"男\"); printf(\"\是否健在(1-健在,0-去世):\"); if(Tree->death==1) printf(\"1\"); else if(Tree->death==0) printf(\"0\"); } } return; } if(NewNode==NULL)//判断它是不是根节点如果是的话就没有父 母兄弟信息 printf(\"\\n\是这个家谱图里最年长的人\ 精心整理 else { if (NewNode->Kind=='G'||NewNode->Kind=='g') //判断父亲节 点是父亲还是母亲 { printf(\"\\n\母亲 姓名:%s\输出他(她)的父母亲的信息 } else { } if(Tree->NextNode[0]!=NULL) //判断他(她)是否有配偶 { if(flag==1)//输出他(她)的配偶的信息 printf(\"\\n\丈夫 姓名:%s\ printf(\"\\n\母亲 姓名:%s\ printf(\"\\n\父亲 姓名:%s\ printf(\"\\n\父亲 姓名:%s\ else printf(\"\\n\妻子 姓名:%s\ if (Tree->ChildNum>0) //判断他(她)是否有孩子 { 精心整理 息 for(i=1;i<=Tree->ChildNum;i++) { printf(\"\\n\姓名:%s 性 printf(\"\\n\的孩子的信息如下:\"); //输出他(她)的孩子的信 别:\ if (Tree->NextNode[i]->Kind=='G'||Tree->Kind=='g') printf(\"女\"); else printf(\"男\"); printf(\"\是否健在(1-健在,0-去世):\"); if(Tree->death==1) printf(\"1\"); else if(Tree->death==0) printf(\"0\"); } } else printf(\"\\n\%s至今还没有孩子\ } else } 精心整理 printf(\"\\n\%s至今还没有配偶和孩子\\n\ } TreeNode * SearchTree1(TreeNode *Tree,char birth[],int length) { int i; TreeNode *NewNode; if(strcmp(Tree->birthday,birth)==0) { if(length==0) FLAG=1; } if(Tree->NextNode[0]==NULL) return NULL; else FLAG=0; return Tree; for(i=0;i<=Tree->ChildNum;i++) { if (i==0) NewNode=SearchTree1(Tree->NextNode[i],birth,0); else NewNode=SearchTree1(Tree->NextNode[i],birth,20); if (NewNode!=NULL) return NewNode; 精心整理 } void OutPutMessage1(TreeNode * Tree,char birth[],int length) { int flag=0,i; TreeNode *NewNode; } return NULL; printf(\"\\n\\n\-----*----*----*----*----*----*----*----*----*----*----\"); if(Tree==NULL) { printf(\"\\n\\n\****该家谱图中没有出生日期为%s这个人的信息请确认是否输入错误*****\\n\ return; } printf(\"\\n\\n\您所要找的人已经找到信息如下所示:\"); printf(\"\\n\\n\姓名:%s出生日期:%s 家庭住址:%s 性别:%c\ if (Tree->Kind=='G'||Tree->Kind=='g') { flag=1; //标记他(她)的性别 printf(\"女\"); } 精心整理 } void Change(TreeNode * Tree) //修改某个人的信息 { char name[20]; TreeNode * NewNode; printf(\"\\n\请输入你要修改的人的姓名:\\n\\"); scanf(\"%s\ NewNode=SearchTree(Tree,name,20); if(NewNode==NULL) { printf(\"\\n\\n\****该家谱图中没有%s这个人的信息请确认是否 else printf(\"男\"); 输入错误*****\\n\ } void SubMenue1(TreeNode * Tree) //输出副菜单 return; } else { SubMenue1(NewNode); } 精心整理 { char c; int flag,i; char name[20]; char birth[20]; char address1[50]; char Parent[2][20]; TreeNode * NewNode; getchar(); while(1) { system(\"cls\"); printf(\"\\"); printf(\"\\n\\n\ ---*****---请选择你的操作---****--- \"); printf(\"\\n\---*---*---*---A:修改个人的信息---*---*---*---*---*---*---- \"); printf(\"\\n\---*---*---*---B:修改父母的信息 ---*---*---*---*---*---*---- \"); printf(\"\\n\---*---*---*---C:修改子女的信息 ---*---*---*---*---*---*---- \"); 精心整理 printf(\"\\n\---*---*---*---D:退出 -*---*---*---*---*---*---*---*---*----\\n\\"); c=getchar(); switch(c) { case 'A': printf(\"\\n\\n\请输入修改的姓名:如果不需要修改就输入‘0’然后按Enter键继续\\n\\"); scanf(\"%s\ if(strcmp(name,\"0\")!=0) strcpy(Tree->Name,name); printf(\"\\n\\n\是否要修改性别:如果需要就输入'1'不需要修改就输入'0'然后按Enter键继续\\n\\"); scanf(\"%d\ if (flag==1) { } printf(\"\\n\\n\请输入修改的出生日期:如果不需要修改就输入‘0’if(Tree->Kind=='G'||Tree->Kind=='g') Tree->Kind='B'; else Tree->Kind='G'; 然后按Enter键继续\\n\\"); 精心整理 scanf(\"%s\ if(strcmp(birth,\"0\")!=0) strcpy(Tree->birthday,birth); printf(\"\\n\\n\请输入修改的家庭地址:如果不需要修改就输入‘0’ 然后按Enter键继续\\n\\"); scanf(\"%s\ if(strcmp(address1,\"0\")!=0) strcpy(Tree->address,address1); printf(\"\\n\\n\个人信息修改成功\"); break; case 'B': if(Tree->Parent==NULL) //判断是不是头节点 { printf(\"\\n\是这个家谱图里最顶端的人没有父母信息!\ break; } if (FLAG==1) //判断是不是入赘或加入此间的 { if(Tree->Kind=='G'||Tree->Kind=='g') { printf(\"\\n\\n\她是嫁入此间的所以父母信息不在家谱内包括\"); } 精心整理 else { printf(\"\\n\\n\他是入赘此间的所以父母信息不在家谱内包括\"); } break; } if(Tree->Parent->Kind=='G'||Tree->Parent->Kind=='g') { strcpy(Parent[0],\"母亲\"); strcpy(Parent[1],\"父亲\"); } else { strcpy(Parent[0],\"父亲\"); strcpy(Parent[1],\"母亲\"); } printf(\"\\n\\n\请输入%s要修改的姓名:如果不需要修改就输入‘0’ 然后按Enter键继续\\n\\ scanf(\"%s\ if(strcmp(name,\"0\")!=0) strcpy(Tree->Parent->Name,name); 精心整理 printf(\"\\n\\n\请输入%s要修改的姓名:如果不需要修改就输入‘0’ 然后按Enter键继续\\n\\ scanf(\"%s\ if(strcmp(name,\"0\")!=0) strcpy(Tree->Parent->NextNode[0]->Name,name); printf(\"\\n\\n\-------------父母的信息修改成功----------------\"); break; case 'C': if(Tree->ChildNum==0) { printf(\"\\n\\n\至今还没有子女\"); break; } if (Tree->Parent !=NULL) if (strcmp(Tree->Name,Tree->Parent->NextNode[0]->Name)==0)//如果他是入赘或者是嫁入的就需用配偶节点完成修改 { Tree=Tree->Parent; } for(i=1;i<=Tree->ChildNum;i++) { 精心整理 printf(\"\\n\\n\请输入%s修改的姓名:如果不需要修改就 输入‘0’然后按Enter键继续\\n\\ scanf(\"%s\ if(strcmp(name,\"0\")!=0) strcpy(Tree->NextNode[i]->Name,name); printf(\"\\n\\n\是否要修改性别:如果需要就输入'1'不需要修改就输入'0'然后按Enter键继续\\n\\"); scanf(\"%d\ if (flag==1) { if(Tree->NextNode[i]->Kind=='G'||Tree->NextNode[i]->Kind=='g') Tree->NextNode[i]->Kind='B'; else Tree->NextNode[i]->Kind='G'; } } printf(\"\\n\\n\---------------子女的信息修改成功----------------\"); break; case 'D': printf(\"\\n\\n\----------------本项服务到此结束-----------------\"); break; 精心整理 case '\\n': break; default: printf(\"\\n\\n\--------对不起!你的选择不在服务范围之 内!---------\"); printf(\"\\n\-----------请您再次选择所需的服务项!-------------\"); printf(\"\\n\------------------谢谢合作!----------------------\\n\\"); break; } if (c=='D'||c=='d') break; printf(\"\\n\\n\--------------请按Enter键继续操作--------------\"); getchar(); getchar(); } } void SaveFamily(TreeNode *root)//保存家谱至指定文件 { char saveFileName[maxFileNameLen]; FILE* fp; TreeNode *queue[50], *head; int i, front, rear;//队列的头指针,尾指针 精心整理 printf(\" ***** 保存家谱 *****\\n\\n\"); //if(root==NULL) if(root == NULL) { } TipForSaveFilePosition;//文件及其绝对路径格式 scanf(\"%s\getchar(); fp = fopen(saveFileName, \"w\");//不存在则新建。存在,则从文件起始printf(\"\\家谱中无成员,无法保存!\\n\"); return; 位置写,原内容将被覆盖。 if(fp == NULL) { } else printf(\"\\新建文件成功,文件及其路径为: %s\\n\printf(\"\\新建文件失败!\\n\"); return ; saveFileName); /*利用宽度优先搜索遍历家族多叉树*/ 精心整理 fwrite(root, sizeof(TreeNode), 1, fp); //将根结点存入文件(二进制形式) front = rear = 0;//初始化空队 queue[rear++] = root;//根结点进队 while(front != rear)//队列不为空 { head = queue[front++];//队头元素出队 if (head->NextNode[0] != NULL) { } for(i=1; i<=head->ChildNum; i++) { fwrite(head->NextNode[0], sizeof(TreeNode), 1, fp); fwrite(head->NextNode[i], sizeof(TreeNode), 1, fp); } void ReadFamily(tree *root)//从指定文件中读取家谱 { 精心整理 } fclose(fp); fp = NULL; } queue[rear++] = head->NextNode[i]; FILE* fp; char readFileName[50]; tree queue[50],head; int i, front, rear; printf(\" ***** 读取家谱 *****\\n\\n\"); printf(\"\\输入文件名及其路径,以便从中读取家谱。\\n\"); TipForReadFilePosition; scanf(\"%s\getchar(); fp = fopen(readFileName, \"r\");//为读而打开文本文件(文件必须已存在) if(fp == NULL) { } /*一边从文件读取结构体变量,一边重新建树*/ *root = (tree)malloc(sizeof(TreeNode)); if(*root == NULL) printf(\"\\只读形式打开文件失败!\\n\"); return; { printf(\"\\重建树时为根结点分配内存失败!\\n\"); return; 精心整理 } fread(*root, sizeof(TreeNode), 1, fp); front = rear = 0;//初始化空队 queue[rear++] = *root;//根结点进队 while(front!=rear) { head = queue[front++]; if (head->NextNode[0] != NULL) { } for (i = 1; i<=head->ChildNum; i++) { head->NextNode[i] = (tree)malloc(sizeof(TreeNode)); if (head->NextNode[i] == NULL) { head->NextNode[0] = (tree)malloc(sizeof(TreeNode)); if (head->NextNode[0] == NULL) { } fread(head->NextNode[0], sizeof(TreeNode), 1, fp); printf(\"\\重建树时分配内存失败!\\n\"); return; 精心整理 } } fclose(fp); fp = NULL; } } fread(head->NextNode[i], sizeof(TreeNode), 1, fp); head->NextNode[i]->Parent = head; queue[rear++] = head->NextNode[i]; printf(\"\\重建树时分配内存失败!\\n\"); return; 六、 总结 本次数据结构课程设计我选的题目是家谱管理系统,历时四天,由我和王月 同学一起完成。总体来说这次课程设计还是比较困难的,而且我们选的这个题目在这些题目中也是很有难度的。中间遇到很多困难,但是在我和她一起讨论以及老师的帮助下,最终还是顺利的完成了。 刚一开始选题目的时候,我并没有怎么在意选什么,只是随便选了一个,到后来才发现选的这个题目非常难。经过分析,发现这个题目需要用到树,而树我又没有学好,所以写的时候非常吃力。最一开始,我用的是二叉树来存储,后来写到一半发现写不下去了,用递归创建函数始终不合适,最后不得不放弃。于是我在网上开始查找资料,不过查到的资料大多于本次实验不相符,还有一些也是看不懂。只有一个,我发现他是用的多叉树,看了一会发现也能理解。于是打算用多叉树来储存。可是又不知道该如何写起,但还是在网上查了多叉树的递归创建方法就开始写了。 在上机前一天晚上,王月给我发来了他写的程序,除了存盘和读盘,其他的功能基本都实现了。我拿来他的和我对比,发现我们写的大同小异,于是我结合着她的将我的改了一下,基本的功能也能实现了。接下来就是最重要的模块了,也是最麻烦的,存盘和读盘。我和王月同学参考了去年的课程设计的保存和读取。但是那是顺序表的保存和读取,和我们用到的不尽相同。这个时候我们已经没有 精心整理 思路,所以我们向老师求助。老师给我们讲了一些关于存和读的知识,又让我们看了一下书,我们总算大体了解了一下这个知识。接下来我们在网上查找资料,最终终于写出来了存盘和读盘。但是运行的时候发现又有问题了,在表面上看来是只能存不能读。于是我们向老师求助,老师看了我们的程序之后,建议我们换一种方式存盘和读盘,将节点存起来,然后读盘时读一个就把他放在树里。晚上回去,我对我的函数仔细看了一下,突然发现了问题。我的程序存盘也是有问题的。循环内写入文件少一次,或者说是次数不固定。因为我父亲节点的第一个节点如果有配偶,就存配偶,没有的话存子女,很随机。我发现了这个漏洞之后,想了好久才想出解决方法。我把父节点的第一个节点单独存,不让他入队,然后把第二个后继一直到最后一个循环存。这样果然解决了我们存读盘的问题。完成之后,我们的程序也算是大功告成了。 通过这次课程设计,我学到了很多课本里学不到的知识。比如多叉树的创建以及遍历,还有树的保存与读取。而且,数据结构这门课对我们来说非常重要,这是我们以后学习和运用的基础。以后我们还是要认真学习,多多探索其他知识,使我们的大学生活变得更丰富多彩。 精心整理 因篇幅问题不能全部显示,请点此查看更多更全内容