数据结构家谱管理系统.docx
- 文档编号:10694362
- 上传时间:2023-02-22
- 格式:DOCX
- 页数:35
- 大小:93.77KB
数据结构家谱管理系统.docx
《数据结构家谱管理系统.docx》由会员分享,可在线阅读,更多相关《数据结构家谱管理系统.docx(35页珍藏版)》请在冰豆网上搜索。
数据结构家谱管理系统
《项目实训二》
项目名称__家谱管理系统__
姓 名 _____________
班 级_________________
学 号 __________________
指导教师______________
问题描述:
家谱用于记录某家族历代家族成员的情况与关系。
现编制一个家谱资料管理系统,实现对一个家族所有的资料进行收集整理。
实现对家庭成员信息的建立、查找、插入、修改、增加、删除、更新、统计等等功能。
目的和要求:
目的:
1、能根据具体问题的具体情况,结合数据结构课程中的基本理论和基本算法,分析并正确确定数据的逻辑结构,合理地选择相应的存储结构,并能设计出解决问题的有效算法。
2、提高程序设计和调试能力。
通过上机学习,验证自己设计的算法的正确性。
学会有效利用基本调试方法。
3、初步掌握软件开发过程中问题分析、系统设计、程序编码、测试等基本方法和技能。
4、培养根据选题需要选择学习书籍,查阅文献资料的自学能力。
要求:
用于记录某家族历代家族成员的情况与关系。
现编制一个家谱资料管理系统,实现对一个家族所有的资料进行收集整理。
支持对家谱的增加,删除,更新,统计等。
软件环境:
MicrosoftVisualStudio2010
流程设计:
模块划分:
1、统计模块
(1)统计家族总人数、健在人数、几代人
(2)主要函数:
intGeneration(Node*root);//这个家族共有几代人
intNumberOfPeople();//家族的总人数
intLifeNum();//健在人数
(3)实现方法:
静态成员变量
(4)实现结果:
2、更新模块
(1)创建家谱、增加成员、删除成员、成员改名
(2)主要函数:
Node*Creat();//构造函数调用
voidAddNewPeople(Node*root,stringFatherName,stringNAme);//增加新的家族成员
intDeletePeople(Node*root,stringFatherName,stringDeletepeople);//删除家族成员
intSetNewName(Node*root,stringNAme,stringNewName);//更改姓名
(3)实现方法:
创建家谱和成员改名主要通过递归调用;增加成员和删除成员主要通过栈的非递归调用。
(4)实现结果:
3、查询模块
(1)查询成员详细信息、查询成员的孩子以及孩子的详细信息
(2)主要函数:
intMessage(Node*root,stringName);//显示该成员的基本信息
intFindChild(Node*root,stringNAme);//显示孩子信息
(3)实现方法:
通过递归调用,找到成员,输出相应的信息
(4)实现结果:
4、显示模块
(1)前序、中序、后序遍历家谱
(2)主要函数:
voidPreOrder(Node*root);//前序递归遍历输出家谱
voidInOrder(Node*root);//中序递归遍历输出家谱
voidPostOrder(Node*root);//后序递归遍历输出家谱
(3)实现方法:
递归遍历
(4)实现结果:
5、文件模块
(1)保存到文件、从文件读取
(2)主要函数:
voidSaveToFile(Node*root);//保存到文件
voidFileToFamilyTree(Node*root);//从文件中读取
(3)实现方法:
文件流
(4)实现结果:
数据结构实现:
1、生日结构体
structBirthDay
{
intyear;
intmonth;
intday;
friendistream&operator>>(istream&is,BirthDay&b);
friendostream&operator<<(ostream&os,constBirthDay&b);
};
2、信息结构体(家族成员的基本信息)
structInformation
{
stringname;//姓名
stringbirthPlace;//出生地
BirthDaybirthDay;//生日
stringsex;//性别
stringeducation;//学历
stringjob;//工作
stringfather;//父亲
stringspouse;//配偶
charlife;//是否健在
};
3、二叉树结点结构体
structNode
{
Informationdata;//个人信息
Node*child;//第一个孩子
Node*brother;//兄弟
};
4、家谱类(二叉树结构、左孩子,右兄弟)
classFamilyTree
{
private:
Node*root;
Node*Creat();//构造函数调用
voidRelease(Node*root);//析构函数调用
staticintNumberofpeople;//计算总人数,NumberOfPeople()调用
staticintLifePeopele;//计算健在人数,LifeNum()调用
public:
FamilyTree();//构造函数,初始化一棵树,其前序序列由键盘输入
~FamilyTree();//析构函数,释放链表中各结点的存储空间
voidSetNode(Node*root);//设置结点信息
Node*Getroot();//获取根结点
voidPreOrder(Node*root);//前序递归遍历输出家谱
voidInOrder(Node*root);//中序递归遍历输出家谱
voidPostOrder(Node*root);//后序递归遍历输出家谱
intGeneration(Node*root);//这个家族共有几代人
intNumberOfPeople();//家族的总人数
intLifeNum();//健在人数
voidPrintMessage(Node*root);//输出基本信息
intMessage(Node*root,stringName);//显示该成员的基本信息
Node*PreFindFather(Node*root,stringFatherName);//给定元素值查找父亲结点指针位置并返回其指针,此方法采用的先序遍历
Node*PreFindBrother(Node*root,stringFatherName);//给定元素值查找兄弟结点指针位置并返回其指针,此方法采用的先序遍历
voidAddNewPeople(Node*root,stringFatherName,stringNAme);//增加新的家族成员
intDeletePeople(Node*root,stringFatherName,stringDeletepeople);//删除家族成员
intSetNewName(Node*root,stringNAme,stringNewName);//更改姓名
intFindChild(Node*root,stringNAme);//显示孩子信息
voidSaveToFile(Node*root);//保存到文件
voidFileToFamilyTree(Node*root);//从文件中读取
};
调试分析:
1、问题:
在创建家谱时,询问用户是否需要继续添加成员,只要用户不输入”#”就继续添加。
解决方案:
增加if语句判断条件,只要输入的不是”Y”,”y”,”#”,就请用户重新输入。
2、问题:
计算总人数和健在人数,因为存在增加和删除函数,多次调用计算函数。
解决方案:
在家谱类中使用静态成员变量
3、问题:
在输入和输出成员信息中的生日,生日使用的是生日结构体变量,输入输出包括年、月、日。
解决方案:
使用友元输入输出重载
4、问题:
在输入生日时,输入数字程序正常运行,输入其他字符,程序会出现死循环。
解决方案:
()判断输入是否正确,()为了使输入错误能重新输入,将错误标识符改为0,()清空流。
5、问题:
在输入一些信息是,询问用户是否确认一些信息时,请用户输入‘y、‘n’,但是用户有时会输入大写。
解决方案:
使用toupper()函数,将用户输入的确认信息转换成大写字母。
6、问题:
在增加孩子时,只能添加长子,添加第二个孩子、第三个等等,会出现错误。
解决方案:
添加一个寻找兄弟指针的函数,如果要添加孩子的成员,已经有了孩子,则通过调用兄弟指针函数来增加孩子。
7、问题:
保存到文件和读取文件时,会出现输入路径错误的情况。
解决方案:
通过调用_access()函数,判断输入路径是否正确。
8、问题:
读取文件时,cin的>>重载会跳过空白字符,包括回车符。
解决问题:
使用()函数接收回车。
9、问题:
删除成员时,删除能够成功,但会出现空指针错误。
解决方案:
在delete该成员时,需要将指向该成员的指针置空。
10、问题:
在主函数中,通过请用户输入数字,来选择相应的操作,当用户误输入的为选择以外的字符时,会结束程序运行。
解决方案:
与解决方案4相同。
实验结果及分析
1、创建家谱
2、保存到文件
3、读取文件
4、增加成员
5、基本信息
6、查询成员信息
7、成员改名
8、遍历家谱
9、查询孩子信息
10、删除成员
收获:
本次实训在我们为期两周的时间里进行,通过自己的不断学习、请教和老师的指导,完成了关于家谱资料管理的设计。
前期主要是准备阶段,运用哪些技术,中期实践阶段,通过几天的上机编写代码,然后完成,后期完善阶段,对一些难点和重点再细化,和做一些数据输入时的异常处理。
最后进行答辩阶段。
通过这次实训的互相帮助学习的过程,自己看书学习的经验,以及从网上以及其他各种途径获得信息和知识的经验。
理论与实际相结
合的设计,锻炼了我综合运用所学的基础知识,解决实际问题的能力,同时也提高我查阅文献资料、对程序整体的把握等其他能力水平。
而且通过对整体的掌控,对局部的取舍,以及对细节的斟酌处理,都使我的能力得到了锻炼,我的各方面经验都得到了极大的丰富。
附录全部代码
#ifndefFAMILYTREE_H
#defineFAMILYTREE_H
#include
#include
#include
#include<>
#include
#include
usingnamespacestd;
structBirthDay{
intyear;
intmonth;
intday;
friendistream&operator>>(istream&is,BirthDay&b);
friendostream&operator<<(ostream&os,constBirthDay&b);
};
structInformation
{
stringname;
stringbirthPlace;
BirthDaybirthDay;
stringsex;
stringeducation;
stringjob;
stringfather;
stringspouse;
charlife;
};
structNode
{
Informationdata;
Node*child;
Node*brother;
};
classFamilyTree
{
private:
Node*root;
Node*Creat();
voidRelease(Node*root);
staticintNumberofpeople;
staticintLifePeopele;
public:
FamilyTree();
~FamilyTree();
voidSetNode(Node*root);
Node*Getroot();
voidPreOrder(Node*root);
voidInOrder(Node*root);
voidPostOrder(Node*root);
intGeneration(Node*root);
intNumberOfPeople();
intLifeNum();
voidPrintMessage(Node*root);
intMessage(Node*root,stringName);
Node*PreFindFather(Node*root,stringFatherName);
Node*PreFindBrother(Node*root,stringFatherName);
voidAddNewPeople(Node*root,stringFatherName,stringNAme);
intDeletePeople(Node*root,stringFatherName,stringDeletepeople);
intSetNewName(Node*root,stringNAme,stringNewName);
intFindChild(Node*root,stringNAme);
voidSaveToFile(Node*root);
voidFileToFamilyTree(Node*root);
};
#endif
#include""
intFamilyTree:
:
Numberofpeople=0;
intFamilyTree:
:
LifePeopele=0;
//生日结构体变量输入输出友元重载
istream&operator>>(istream&is,BirthDay&b)
{
is>>>>>>;
returnis;
}
ostream&operator<<(ostream&os,constBirthDay&b)
{
os<<<<"-"<<<<"-"<<;
returnos;
}
FamilyTree:
:
FamilyTree()//构造函数,初始化一棵树,其前序序列由键盘输入
{
this->root=Creat();
}
FamilyTree:
:
~FamilyTree()//析构函数,释放链表中各结点的存储空间
{
Release(root);
}
Node*FamilyTree:
:
Getroot()//获取根结点
{
returnroot;
}
Node*FamilyTree:
:
Creat()//构造函数调用
{
Node*root;
stringch;
cout<<"请问是否创建(是:
“y”,否:
“#”):
";
cin>>ch;//输入名字
if(ch!
="y")//异常处理
{
if(ch!
="Y")
if(ch!
="#")
{
intt=1;
do
{
cout<<"\n输入不明确,请重新输入!
!
"< cout<<"请问是否创建(是: “y”,否: “#”): "; cin>>ch; if((ch=="y")||(ch=="Y")||(ch=="#")) t=0; }while(t==1); } } if(ch=="#")root=NULL; else { root=newNode;//申请结点内存空间 SetNode(root);//设置结点内容 root->child=Creat();//该结点的孩子 root->brother=Creat();//该结点的兄弟 } returnroot;//返回结点 } voidFamilyTree: : Release(Node*root)//析构函数调用 { if(root! =NULL) { Release(root->child);//释放左孩子 Release(root->brother);//释放右兄弟 deleteroot; } } voidFamilyTree: : SetNode(Node*root)//设置结点信息 { Numberofpeople++; cout<<"请输入家庭成员的基本信息"< cout<<"姓名: "; cin>>root->; cout<<"出生地: "; cin>>root->; cout<<"生日(数字、年月日以空格或者回车间隔): "; while (1) { cin>>root->; if()) { cout<<"输入有错! ! 请重新输入生日(数字): "< ();//输入错误则能重新输入 ();//清空流 } else break; } //isdigit异常处理生日输入,若参数c为阿拉伯数字0~9,则返回非0值,否则返回NULL。 /*inti; for(i=0;root->[i]! =0;++i) { if(isdigit(root->[i])==0) { cout<<"\n输入不明确,请重新输入! ! "< break; } }*/ cout<<"性别: "; cin>>root->; cout<<"学历: "; cin>>root->; cout<<"工作: "; cin>>root->; cout<<"父亲: "; cin>>root->; cout<<"配偶(有多任配偶则以“,”或者“、”间隔): "< cin>>root->; cout<<"是否健在(y是,n否): "; cin>>root->; if(toupper(root->! ='Y')//异常处理 { if(toupper(root->! ='N'){ intt=1; do { cout<<"\n输入不明确,请重新输入! ! "< cout<<"是否健在(y是,n否): "; cin>>root->; if((toupper(root->=='Y')||(toupper(root->=='N')) t=0; }while(t==1); } } if(toupper(root->=='Y') LifePeopele++; } voidFamilyTree: : PreOrder(Node*root)//前序递归遍历输出家谱 { if(root==NULL) return; else { cout< PreOrder(root->child); PreOrder(root->brother); } } voidFamilyTree: : InOrder(Node*root)//中序递归遍历输出家谱 { if(root==NULL) return; else { InOrder(root->child); cout< InOrder(root->brother); } } voidFamilyTree: : PostOrder(Node*root)//后序递归遍历输出家谱 { if(root==NULL) return; else { PostOrder(root->child); PostOrder(root->brother); cout< } } intFamilyTree: : Generation(Node*root)//这个家族共有几代人 { intl;//l左孩子 if(root==NULL)//这个家族为空,返回0 return0; else { l=Generation(root->child);//左孩子的 returnl+1; } } //intnumberofpeople=0; intFamilyTree: : NumberOfPeople()//家族的总人数 { if(root==NULL)//家族人数为0 return0; /*else { if(root! =NULL) numberofpeople++; NumberOfPeople(root->child); NumberOfPeople(root->brother); } returnnumberofpeople;*/ else returnNumberofpeople; } //intcount=0; intFamilyTree: : LifeNum()//健在人数 { if(root==NULL)//-1表示这个家族不存在 return-1; /*else { if(toupper(root->=='Y') count++; LifeNum(root->child); LifeNum(root->brother); } returncount;*/ returnLifePeopele; } voidFamilyTree: : PrintMessage(Node*root)//输出基本信息 { if(root==NULL) return; else { cout<<"姓名: "< cout<<"\t\t性别: "< cout<<"\t\t配偶: "< cout<<"出生地: "< cout<<"\t\t生日: "<
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 数据结构 家谱 管理 系统