数据结构课设报告Word下载.docx
《数据结构课设报告Word下载.docx》由会员分享,可在线阅读,更多相关《数据结构课设报告Word下载.docx(56页珍藏版)》请在冰豆网上搜索。
3、统计功能
3.1、统计家谱成员的总人数
3.2、统计从事某种职业的人数
3.3、综合统计
其他功能
要求:
1、用文件保存家谱信息
2、图形方式显示家谱
二.系统总体设计(模块结构图)
程序入口
建立家谱
读取文件
保存家谱
添加结点
修改结点
删除结点
输出家谱
统计
基本查询
关系查询
祖先列表
两人关系
三.算法和数据结构的设计
由于家族关系本身具有树的特点,所以家族关系在内存的数据结构首选为树。
家庭成员之间的关系,用树形结构(家族树)表示,通过左孩子右兄弟的方式变为二叉树,创建的过程实际上就是二叉树的添加结点的过程,根据父亲的名字添加在父亲结点的左边。
家谱的创建
FamilyTree:
:
FamilyTree()
{
T=NULL;
//开始为空家谱
}
家谱结点的添加
voidFamilyTree:
Add(personparent,personaddNode)
//将addnode添加到parent作为parent的孩子结点
intn=0;
addNode->
firstchild=addNode->
nextsibling=NULL;
//初始时firstchild同nextsibling都为空
parent=parent;
if(parent==NULL)//如果父结点空
{
if(T==NULL)//如果根结点空
addNode->
data.Depth=n;
T=addNode;
//将addnode赋给根结点
return;
}
n=T->
data.Depth+1;
//否则将原来的根结点成为新根结点的孩子
T->
//并使原来根结点的depth值加1
firstchild=T;
parent=addNode;
strcpy(addNode->
data.parentname,parent->
data.name);
n=parent->
//将depth值加1
if(parent->
firstchild==NULL)//如果parent无孩子,把addNode加入其firstchild
parent->
firstchild=addNode;
else
InsertSibling(parent->
firstchild,addNode);
//否则插入到相应的兄弟结点中去
}
家谱结点的修改就是将结点的指针传入,更新数据就可完成,代码如下:
Modify(person&
curnode,personnewnode)
//修改某个人的信息
strcpy(curnode->
data.name,newnode->
data.birthplace,newnode->
data.birthplace);
data.sex,newnode->
data.sex);
data.occupation,newnode->
data.occupation);
data.education,newnode->
data.education);
data.top_headship,newnode->
data.top_headship);
curnode->
data.height=newnode->
data.height;
data.birthdate=newnode->
data.birthdate;
data.deathdate=newnode->
data.deathdate;
家谱结点的删除是删除该结点及这个结点对应的所有孩子结点的信息,释放内存空间就可完成,代码如下:
Delete(person&
rootNode)
//删除rootnode结点以及他的所有孩子结点
if(rootNode->
parent)//rootnode不是根结点
parent->
firstchild==rootNode)//如果rootnode为其父结点的第一个孩子
rootNode->
firstchild=rootNode->
nextsibling;
//将rootnode的nextsibling结点变为rootnodeparent结点的firstchild结点
personp=rootNode->
firstchild;
//否则,找到rootnode在兄弟中的位置
for(;
p->
nextsibling!
=rootNode;
p=p->
nextsibling)
;
p->
nextsibling=rootNode->
//插入到兄弟中
PostOrderTraverse(rootNode->
firstchild,DestroyNode);
//调用后序遍历删除rootnode的所有孩子结点
if(rootNode==T)//删除rootnode结点
DestroyNode(T);
DestroyNode(rootNode);
家谱信息的存储是按先序遍历的方式依次存入硬盘的,读取的时候,将第一个结点的信息对应根结点,后面依次根据父亲的姓名使用插入函数完成家谱的重建,代码如下:
SaveFamilyTree()
//保存二叉树到文件
fstreamf("
1.dat"
ios:
binary|ios:
out);
//以二进制写方式打开文件
if(!
f)
cerr<
<
"
文件打开失败!
endl;
//如果不能打开,显示出错信息
return;
}
PreOrderTraverse(f,T,SaveNode);
//调用先序遍历写二叉树信息到文件
f.close();
//关闭文件
//person&
t=FamilyTree:
GetRoot();
//返回家谱的根结点
//returnt;
家谱信息的遍历
主要使用递归的方式遍历家谱树,代码入下:
先序遍历:
PreOrderTraverse(fstream&
f,person&
T,void(__cdecl*Visit)(fstream&
T))
//先序遍历二叉树,并执行visit函数
if(T)
(*Visit)(f,T);
PreOrderTraverse(f,T->
firstchild,Visit);
nextsibling,Visit);
后序遍历:
PostOrderTraverse(person&
T,void(__cdecl*Visit)(person&
//后序遍历二叉树,并执行visit函数
PostOrderTraverse(T->
(*Visit)(T);
成员的查找
查找部分涉及的查找方法多样,这里用按姓名查找来代表,其他查找使用的算法思想是类似的,使用递归的方法,代码如下:
FindByName(person&
T,person&
Tname,char*name)//searchthenameininfofromrootT
//查找姓名=name的人,若在家谱中,用Tname返回,否则Tname为空,Tname初始为空
if(strcmp(T->
data.name,name)==0)//用string库的strcmp()比较两个字符串,若相等,则找到符合条件的
Tname=T;
else
{
FindByName(T->
firstchild,Tname,name);
//对T的firstchild递归搜索
nextsibling,Tname,name);
//对T的nextsibling递归搜索
}
四.程序测试及结果分析
程序在VC里编译连接运行以后,显示主界面如下:
选择相应的操作数,以回车键结束。
例如新建家谱时,出现如下界面,按提示输入各种信息。
添加成员,类似界面,按照操作提示输入家谱成员信息。
载入家谱:
显示家谱所有信息:
删除彭了及其子孙后的结果如下:
删除成功。
重新保存家谱并退出:
退出后再进入,显示家谱所有成员信息,可以看出文件已经被保存。
经过测试,功能都已实现。
五.复杂度分析
1)NewFamilyTree()O
(1)
2)FamilyTree()O
(1)
3)CreateFamilyTree()O(n)
4)DestroyNode(person&
pnode)O
(1)
5)DestroyFamilyTree()O(n)
6)PostOrderTraverse(person&
T))O(n)
7)PreOrderTraverse(fstream&
T))O(n)
8)SaveNode(fstream&
f,person&
pnode)O
(1)
9)SaveFamilyTree()O(n)
10)ReadNode(fstream&
11)FindByName(person&
Tname,char*name)O(n)
12)FindByBirthplace(person&
Tname,char*birthplace)O(n)
13)FindByBirthday(person&
Tname,Dateday1)O(n)
14)FindByDeathday(person&
Tname,Dateday1)O(n)
15)FindBySex(person&
Tname,char*sex)O(n)
16)FindByHeight(person&
Tname,inth)O(n)
17)FindByAddress(person&
Tname,char*address)O(n)
18)FindByEducation(person&
Tname,char*edu)O(n)
19)FindByOccupation(person&
Tname,char*job)O(n)
20)FindByTopHeadship(person&
Tname,char*top)O(n)
21)AddOperation()O
(1)
22)Display(personinfo)O
(1)
23)IsDateValid(Datedate)O
(1)
24)CompareDate(Datedate1,Datedate2)O
(1)
25)IsLeapYear(intyear)O
(1)
26)InsertSibling(person&
firstchild,personinsertsibling)O
(1)
27)Delete(person&
rootNode)O(n)
28)Modify(person&
curnode,personnewnode)O
(1)
29)DisplayTree(person&
T)O(n)
30)Add(personparent,personaddNode)O
(1)
31)FindByRelationship(personpnode)O(n)
32)Ancestor(personpnode)O
(1)
33)Relationship(personpnode1,personpnode2)O(n)
34)InputData(person&
35)InputDate(Date&
day)O
(1)
36)Age(personpNode)O
(1)
37)Height(personpNode)O
(1)
38)AverageLife(person&
T,int&
personNums,int&
age)O(n)
39)AverageHeight(person&
T,int&
personNums,int&
height)O(n)
40)MaleFemale(person&
maleNum,int&
femaleNum)O(n)
41)FamilyNumber(personpnode)O
(1)
42)TotalFamilyNumber(person&
totalfamily)O(n)
43)TotalFamily(person&
total)O(n)
44)GetRoot()O
(1)
六.源程序
Gneealogy.h
#definemax_char_num100
#definemax_array_num30
//5个include
#include<
stddef.h>
stdio.h>
iostream.h>
iostream>
stdlib.h>
string.h>
fstream.h>
cstdlib>
windows.h>
structDate
intyear;
//年
intmonth;
//月
intday;
//日
};
structInfo
charname[max_char_num];
//姓名
charbirthplace[max_char_num];
//出生地点
Datebirthdate;
//结构date定义的出生日期
Datedeathdate;
//结构date定义的死亡日期
charsex[max_char_num];
//性别
charwife_or_husband[max_char_num];
//配偶
charphone[max_array_num];
//电话
charaddress[max_char_num];
//家庭住址
charresume[max_char_num];
//简历
//其他信息如下
intheight;
//高度
charoccupation[max_char_num];
//职业
chareducation[max_char_num];
//受教育程度
chartop_headship[max_char_num];
//最高职位
charparentname[max_char_num];
//父亲姓名,用于添加节点时用
intDepth;
//二叉树深度,输出二叉树时用
typedefstructCSNode
Infodata;
//个人信息类型结构
CSNode*firstchild,*nextsibling,*parent;
//csnode的第一个孩子节点,下一个兄弟节点,双亲节点
}*person;
classFamilyTree
public:
FamilyTree();
//构造函数
~FamilyTree();
//析构函数
voidNewFamilyTree();
//建立一个空的家谱树
voidCreateFamilyTree();
//从磁盘读取文件建立家谱树
voidDestroyFamilyTree();
//删除家谱树
voidSaveFamilyTree();
//保存家谱树
voidPreOrderTraverse(fstream&
f,person&
T,void(*Visit)(fstream&
T));
//先序遍历家谱树,为保存和显示家谱树作准备
voidPostOrderTraverse(person&
T,void(*Visit)(person&
T));
//后序遍历家谱树,为删除家谱树作准备
voidReadNode(fstream&
pnode);
//从二进制文件读取结点信息以供CreateFamilyTree()建立家谱树
voidFindByRelationship(personpnode);
//按照亲属关系查找某人的父母,孩子,兄弟,若查找成功则显示出来
voidModify(person&
pNode,personnewValue);
//修改某个人的信息
intCompareDate(Datedate1,Datedate2);
////比较两日期大小,若date1比date2早,返回-1;
date1比date2晚,返回1;
date1与date2相等,返回0
voidFindByName(person&
Tname,char*name);
//查找姓名=name的人,若在家谱中,用Tname返回,否则Tname为空,Tname初始为空
voidFindByBirthplace(person&
T,person&
//查找出生地=name的人,若在家谱中,则显示出来,否则显示出错信息,Tname初始为空
voidFindByBirthday(person&
Tname,Datedate);
//查找出生日期=date的人,若在家谱中,则显示出来,否则显示出错信息,Tname初始为空
voidFindByDeathday(person&
//查找死亡日期=date的人,若在家谱中,则显示出来,否则显示出错信息,Tname初始为空
voidFindBySex(person&
//查找性别=name的人,若在家谱中,则显示出来,否则显示出错信息,Tname初始为空
voidFindByHeight(person&
T,person&
Tname,intheight);
//查找身高=height的人,若在家谱中,则显示出来,否则显示出错信息,Tname初始为空
voidFindByEducation(person&
//查找受教育程度=name的人,若在家谱中,则显示出来,否则显示出错信息,Tname初始为空
voidFindByOccupation(person&
//查找职位=name的人,若在家谱中,则显示出来,否则显示出错信息,Tname初始为空
voidFindByTopHeadship(person&
//查找最高职位=name的人,若在家谱中,则显示出来,否则显示出错信息,Tname