return;
}
PreOrderTraverse(f,T,SaveNode);//调用先序遍历写二叉树信息到文件
f.close();//关闭文件
//person&t=FamilyTree:
:
GetRoot();//返回家谱的根结点
//returnt;
}
家谱信息的遍历
主要使用递归的方式遍历家谱树,代码入下:
先序遍历:
voidFamilyTree:
:
PreOrderTraverse(fstream&f,person&T,void(__cdecl*Visit)(fstream&f,person&T))
{
//先序遍历二叉树,并执行visit函数
if(T)
{
(*Visit)(f,T);
PreOrderTraverse(f,T->firstchild,Visit);
PreOrderTraverse(f,T->nextsibling,Visit);
}
}
后序遍历:
voidFamilyTree:
:
PostOrderTraverse(person&T,void(__cdecl*Visit)(person&T))
{
//后序遍历二叉树,并执行visit函数
if(T)
{
PostOrderTraverse(T->firstchild,Visit);
PostOrderTraverse(T->nextsibling,Visit);
(*Visit)(T);
}
}
成员的查找
查找部分涉及的查找方法多样,这里用按姓名查找来代表,其他查找使用的算法思想是类似的,使用递归的方法,代码如下:
voidFamilyTree:
:
FindByName(person&T,person&Tname,char*name)//searchthenameininfofromrootT
{
//查找姓名=name的人,若在家谱中,用Tname返回,否则Tname为空,Tname初始为空
if(T)
{
if(strcmp(T->data.name,name)==0)//用string库的strcmp()比较两个字符串,若相等,则找到符合条件的
Tname=T;
else
{
FindByName(T->firstchild,Tname,name);//对T的firstchild递归搜索
FindByName(T->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,void(__cdecl*Visit)(person&T))O(n)
7)PreOrderTraverse(fstream&f,person&T,void(__cdecl*Visit)(fstream&f,person&T))O(n)
8)SaveNode(fstream&f,person&pnode)O
(1)
9)SaveFamilyTree()O(n)
10)ReadNode(fstream&f,person&pnode)O
(1)
11)FindByName(person&T,person&Tname,char*name)O(n)
12)FindByBirthplace(person&T,person&Tname,char*birthplace)O(n)
13)FindByBirthday(person&T,person&Tname,Dateday1)O(n)
14)FindByDeathday(person&T,person&Tname,Dateday1)O(n)
15)FindBySex(person&T,person&Tname,char*sex)O(n)
16)FindByHeight(person&T,person&Tname,inth)O(n)
17)FindByAddress(person&T,person&Tname,char*address)O(n)
18)FindByEducation(person&T,person&Tname,char*edu)O(n)
19)FindByOccupation(person&T,person&Tname,char*job)O(n)
20)FindByTopHeadship(person&T,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&pnode)O
(1)
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&T,int&maleNum,int&femaleNum)O(n)
41)FamilyNumber(personpnode)O
(1)
42)TotalFamilyNumber(person&T,int&totalfamily)O(n)
43)TotalFamily(person&T,int&total)O(n)
44)GetRoot()O
(1)
六.源程序
Gneealogy.h
#definemax_char_num100
#definemax_array_num30
//5个include
#include
#include
#include
#include
#include
#include
#include
#include
#include
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&f,person&T));//先序遍历家谱树,为保存和显示家谱树作准备
voidPostOrderTraverse(person&T,void(*Visit)(person&T));//后序遍历家谱树,为删除家谱树作准备
voidReadNode(fstream&f,person&pnode);//从二进制文件读取结点信息以供CreateFamilyTree()建立家谱树
voidFindByRelationship(personpnode);//按照亲属关系查找某人的父母,孩子,兄弟,若查找成功则显示出来
voidModify(person&pNode,personnewValue);//修改某个人的信息
intCompareDate(Datedate1,Datedate2);////比较两日期大小,若date1比date2早,返回-1;date1比date2晚,返回1;date1与date2相等,返回0
voidFindByName(person&T,person&Tname,char*name);//查找姓名=name的人,若在家谱中,用Tname返回,否则Tname为空,Tname初始为空
voidFindByBirthplace(person&T,person&Tname,char*name);//查找出生地=name的人,若在家谱中,则显示出来,否则显示出错信息,Tname初始为空
voidFindByBirthday(person&T,person&Tname,Datedate);//查找出生日期=date的人,若在家谱中,则显示出来,否则显示出错信息,Tname初始为空
voidFindByDeathday(person&T,person&Tname,Datedate);//查找死亡日期=date的人,若在家谱中,则显示出来,否则显示出错信息,Tname初始为空
voidFindBySex(person&T,person&Tname,char*name);//查找性别=name的人,若在家谱中,则显示出来,否则显示出错信息,Tname初始为空
voidFindByHeight(person&T,person&Tname,intheight);//查找身高=height的人,若在家谱中,则显示出来,否则显示出错信息,Tname初始为空
voidFindByEducation(person&T,person&Tname,char*name);//查找受教育程度=name的人,若在家谱中,则显示出来,否则显示出错信息,Tname初始为空
voidFindByOccupation(person&T,person&Tname,char*name);//查找职位=name的人,若在家谱中,则显示出来,否则显示出错信息,Tname初始为空
voidFindByTopHeadship(person&T,person&Tname,char*name);//查找最高职位=name的人,若在家谱中,则显示出来,否则显示出错信息,Tname