数据结构家谱管理系统二叉链表.docx

上传人:b****3 文档编号:3714389 上传时间:2022-11-24 格式:DOCX 页数:41 大小:323.80KB
下载 相关 举报
数据结构家谱管理系统二叉链表.docx_第1页
第1页 / 共41页
数据结构家谱管理系统二叉链表.docx_第2页
第2页 / 共41页
数据结构家谱管理系统二叉链表.docx_第3页
第3页 / 共41页
数据结构家谱管理系统二叉链表.docx_第4页
第4页 / 共41页
数据结构家谱管理系统二叉链表.docx_第5页
第5页 / 共41页
点击查看更多>>
下载资源
资源描述

数据结构家谱管理系统二叉链表.docx

《数据结构家谱管理系统二叉链表.docx》由会员分享,可在线阅读,更多相关《数据结构家谱管理系统二叉链表.docx(41页珍藏版)》请在冰豆网上搜索。

数据结构家谱管理系统二叉链表.docx

数据结构家谱管理系统二叉链表

 

《项目实训二》

 

项目名称__家谱管理系统__

    姓  名 _____________

 班  级_________________

    学  号 __________________

    指导教师______________

2018.1

问题描述:

家谱用于记录某家族历代家族成员的情况与关系。

现编制一个家谱资料管理系统,实现对一个家族所有的资料进行收集整理。

实现对家庭成员信息的建立、查找、插入、修改、增加、删除、更新、统计等等功能。

目的和要求:

目的:

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、问题:

在输入生日时,输入数字程序正常运行,输入其他字符,程序会出现死循环。

解决方案:

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

#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

 

Familytree.cpp

#include"Familytree.h"

intFamilyTree:

:

Numberofpeople=0;

intFamilyTree:

:

LifePeopele=0;

//生日结构体变量输入输出友元重载

istream&operator>>(istream&is,BirthDay&b)

{

is>>b.year>>b.month>>b.day;

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->data.name;

cout<<"出生地:

";

cin>>root->data.birthPlace;

cout<<"生日(数字、年月日以空格或者回车间隔):

";

while

(1)

{

cin>>root->data.birthDay;

if(cin.fail())

{

cout<<"输入有错!

请重新输入生日(数字):

"<

cin.clear();//输入错误则能重新输入

cin.sync();//清空流

}

else

break;

}

//isdigit异常处理生日输入,若参数c为阿拉伯数字0~9,则返回非0值,否则返回NULL。

/*inti;

for(i=0;root->data.birthDay[i]!

=0;++i)

{

if(isdigit(root->data.birthDay[i])==0)

{

cout<<"\n输入不明确,请重新输入!

"<

break;

}

}*/

cout<<"性别:

";

cin>>root->data.sex;

cout<<"学历:

";

cin>>root->data.education;

cout<<"工作:

";

cin>>root->data.job;

cout<<"父亲:

";

cin>>root->data.father;

cout<<"配偶(有多任配偶则以“,”或者“、”间隔):

"<

cin>>root->data.spouse;

cout<<"是否健在(y是,n否):

";

cin>>root->data.life;

if(toupper(root->data.life)!

='Y')//异常处理

{

if(toupper(root->data.life)!

='N'){

intt=1;

do

{

cout<<"\n输入不明确,请重新输入!

"<

cout<<"是否健在(y是,n否):

";

cin>>root->data.life;

if((toupper(root->data.life)=='Y')||(toupper(root->data.life)=='N'))

t=0;

}while(t==1);

}

}

if(toupper(root->data.life)=='Y')

LifePeopele++;

}

voidFamilyTree:

:

PreOrder(Node*root)//前序递归遍历输出家谱

{

if(root==NULL)

return;

else

{

cout<data.name<<'\t';

PreOrder(root->child);

PreOrder(root->brother);

}

}

voidFamilyTree:

:

InOrder(Node*root)//中序递归遍历输出家谱

{

if(root==NULL)

return;

else

{

InOrder(root->child);

cout<data.name<<'\t';

InOrder(root->brother);

}

}

voidFamilyTree:

:

PostOrder(Node*root)//后序递归遍历输出家谱

{

if(root==NULL)

return;

else

{

PostOrder(root->child);

PostOrder(root->brother);

cout<data.name<<'\t';

}

}

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->data.life)=='Y')

count++;

LifeNum(root->child);

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 工程科技 > 能源化工

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1