数据结构家谱管理系统二叉链表文档格式.docx
《数据结构家谱管理系统二叉链表文档格式.docx》由会员分享,可在线阅读,更多相关《数据结构家谱管理系统二叉链表文档格式.docx(41页珍藏版)》请在冰豆网上搜索。
2、更新模块
(1)创建家谱、增加成员、删除成员、成员改名
Node*Creat();
//构造函数调用
voidAddNewPeople(Node*root,stringFatherName,stringNAme);
//增加新的家族成员
intDeletePeople(Node*root,stringFatherName,stringDeletepeople);
//删除家族成员
intSetNewName(Node*root,stringNAme,stringNewName);
//更改姓名
创建家谱和成员改名主要通过递归调用;
增加成员和删除成员主要通过栈的非递归调用。
3、查询模块
(1)查询成员详细信息、查询成员的孩子以及孩子的详细信息
intMessage(Node*root,stringName);
//显示该成员的基本信息
intFindChild(Node*root,stringNAme);
//显示孩子信息
通过递归调用,找到成员,输出相应的信息
4、显示模块
(1)前序、中序、后序遍历家谱
voidPreOrder(Node*root);
//前序递归遍历输出家谱
voidInOrder(Node*root);
//中序递归遍历输出家谱
voidPostOrder(Node*root);
//后序递归遍历输出家谱
递归遍历
5、文件模块
(1)保存到文件、从文件读取
voidSaveToFile(Node*root);
//保存到文件
voidFileToFamilyTree(Node*root);
//从文件中读取
文件流
数据结构实现:
1、生日结构体
structBirthDay
{
intyear;
intmonth;
intday;
friendistream&
operator>
>
(istream&
is,BirthDay&
b);
friendostream&
operator<
<
(ostream&
os,constBirthDay&
};
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、问题:
在输入生日时,输入数字程序正常运行,输入其他字符,程序会出现死循环。
cin.fail()判断输入是否正确,cin.clear()为了使输入错误能重新输入,将错误标识符改为0,cin.sync()清空流。
5、问题:
在输入一些信息是,询问用户是否确认一些信息时,请用户输入‘y、‘n’,但是用户有时会输入大写。
使用toupper()函数,将用户输入的确认信息转换成大写字母。
6、问题:
在增加孩子时,只能添加长子,添加第二个孩子、第三个等等,会出现错误。
添加一个寻找兄弟指针的函数,如果要添加孩子的成员,已经有了孩子,则通过调用兄弟指针函数来增加孩子。
7、问题:
保存到文件和读取文件时,会出现输入路径错误的情况。
通过调用_access()函数,判断输入路径是否正确。
8、问题:
读取文件时,cin的>
重载会跳过空白字符,包括回车符。
解决问题:
使用cin.get()函数接收回车。
9、问题:
删除成员时,删除能够成功,但会出现空指针错误。
在delete该成员时,需要将指向该成员的指针置空。
10、问题:
在主函数中,通过请用户输入数字,来选择相应的操作,当用户误输入的为选择以外的字符时,会结束程序运行。
与解决方案4相同。
实验结果及分析
1、创建家谱
2、保存到文件
3、读取文件
4、增加成员
5、基本信息
6、查询成员信息
7、成员改名
8、遍历家谱
9、查询孩子信息
10、删除成员
收获:
本次实训在我们为期两周的时间里进行,通过自己的不断学习、请教和老师的指导,完成了关于家谱资料管理的设计。
前期主要是准备阶段,运用哪些技术,中期实践阶段,通过几天的上机编写代码,然后完成,后期完善阶段,对一些难点和重点再细化,和做一些数据输入时的异常处理。
最后进行答辩阶段。
通过这次实训的互相帮助学习的过程,自己看书学习的经验,以及从网上以及其他各种途径获得信息和知识的经验。
理论与实际相结
合的设计,锻炼了我综合运用所学的基础知识,解决实际问题的能力,同时也提高我查阅文献资料、对程序整体的把握等其他能力水平。
而且通过对整体的掌控,对局部的取舍,以及对细节的斟酌处理,都使我的能力得到了锻炼,我的各方面经验都得到了极大的丰富。
附录全部代码
Familytree.h
#ifndefFAMILYTREE_H
#defineFAMILYTREE_H
#include<
iostream>
string>
cctype>
io.h>
iomanip>
fstream>
usingnamespacestd;
structBirthDay{
#endif
Familytree.cpp
#include"
Familytree.h"
intFamilyTree:
:
Numberofpeople=0;
LifePeopele=0;
//生日结构体变量输入输出友元重载
istream&
b)
is>
b.year>
b.month>
b.day;
returnis;
}
ostream&
os<
b.year<
"
-"
b.month<
returnos;
FamilyTree:
FamilyTree()//构造函数,初始化一棵树,其前序序列由键盘输入
this->
root=Creat();
~FamilyTree()//析构函数,释放链表中各结点的存储空间
Release(root);
Node*FamilyTree:
Getroot()//获取根结点
returnroot;
Creat()//构造函数调用
Node*root;
stringch;
cout<
请问是否创建(是:
“y”,否:
“#”):
;
cin>
ch;
//输入名字
if(ch!
="
y"
)//异常处理
{
if(ch!
Y"
)
if(ch!
#"
{
intt=1;
do
{
cout<
\n输入不明确,请重新输入!
!
endl;
cin>
if((ch=="
)||(ch=="
))
t=0;
}while(t==1);
}
}
if(ch=="
)root=NULL;
else
root=newNode;
//申请结点内存空间
SetNode(root);
//设置结点内容
root->
child=Creat();
//该结点的孩子
brother=Creat();
//该结点的兄弟
//返回结点
voidFamilyTree:
Release(Node*root)//析构函数调用
if(root!
=NULL)
Release(root->
child);
//释放左孩子
brother);
//释放右兄弟
deleteroot;
SetNode(Node*root)//设置结点信息
Numberofpeople++;
请输入家庭成员的基本信息"
姓名:
root->
data.name;
出生地:
data.birthPlace;
生日(数字、年月日以空格或者回车间隔):
while
(1)
cin>
data.birthDay;
if(cin.fail())
{
cout<
输入有错!
请重新输入生日(数字):
cin.clear();
//输入错误则能重新输入
cin.sync();
//清空流
}
else
break;
//isdigit异常处理生日输入,若参数c为阿拉伯数字0~9,则返回非0值,否则返回NULL。
/*inti;
for(i=0;
data.birthDay[i]!
=0;
++i)
if(isdigit(root->
data.birthDay[i])==0)
}*/
性别:
data.sex;
学历:
data.education;
工作:
data.job;
父亲:
data.father;
配偶(有多任配偶则以“,”或者“、”间隔):
data.spouse;
是否健在(y是,n否):
data.life;
if(toupper(root->
data.life)!
='
Y'
)//异常处理
if(toupper(root->
N'
){
intt=1;
do
cin>
if((toupper(root->
data.life)=='
)||(toupper(root->
t=0;
}while(t==1);
LifePeopele++;
PreOrder(Node*root)//前序递归遍历输出家谱
if(root==NULL)
return;
cout<
data.name<
'
\t'
PreOrder(root->
InOrder(Node*root)//中序递归遍历输出家谱
if(root==NULL)
InOrder(root->
PostOrder(Node*root)//后序递归遍历输出家谱
PostOrder(root->
Generation(Node*root)//这个家族共有几代人
intl;
//l左孩子
if(root==NULL)//这个家族为空,返回0
return0;
l=Generation(root->
//左孩子的
returnl+1;
//intnumberofpeople=0;
NumberOfPeople()//家族的总人数
if(root==NULL)//家族人数为0
/*else
if(root!
numberofpeople++;
NumberOfPeople(root->
returnnumberofpeople;
*/
returnNumberofpeople;
//intcount=0;
LifeNum()//健在人数
if(root==NULL)//-1表示这个家族不存在
return-1;
count++;
LifeNum(root->