📄 operationfamilytree.cpp
字号:
// OperationFamilytree.cpp: implementation of the COperationFamilytree class.
//
//////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
///// 家谱操作类实现文件
/////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "Familytree.h"
#include "OperationFamilytree.h"
#include "FileOpenAndSaveDlg.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
COperationFamilytree::COperationFamilytree()
{
//开始为空家谱
T=0;
}
COperationFamilytree::~COperationFamilytree()
{
//释放资源
DestroyFamilytree();
}
void COperationFamilytree::NewFamilytree()
{
//本函数新建一空家谱
DestroyFamilytree(); //删除原有家谱
T=0;
}
int COperationFamilytree::CreateFamilytree(CString filename)
{
//本函数建立一新家谱
DestroyFamilytree(); //建立一新家谱之前,清空原有家谱
FILE* fp;
if((fp=fopen(filename,"r"))==0) //打开文件filename
return READ_FILE_ERROR;
T=new PersonNode; //定义根结点
if(!T)
return NOT_ENOUGH_MEMORY;
T->child=0;
T->sibling=0;
T->parent=0;
Person parentT, temp; //定义两个临时结点
char parentname[MAX_CHARNUM]; //定义一个临时字符串数组
//读取根结点值,(姓名,出生日期(年,月,日),婚否,地址,健在否,(如过世,还有死亡日期))
int result;
result=ReadNode(fp,T,parentname);
if(result==FILE_DATA_NOT_PRACTICAL){
delete T; //若不合法,删除申请的堆空间
T=0;
return result;
}
if(strcmp(T->info.name,parentname)==0){ //根结点名字与其父亲名字相同,说明为空树
delete T;
T=0;
return PEDIGREE_EMPTY;
}
temp=new PersonNode; //申请一结点
if(!temp){ //申请失败
DestroyFamilytree(); //释放申请空间
return NOT_ENOUGH_MEMORY;
}
result=ReadNode(fp,temp,parentname);
while(strcmp(temp->info.name,parentname)&&strcmp(temp->info.name,"end")){ //读取信息结束的条件是两个人的名字同为end
if(result==FILE_DATA_NOT_PRACTICAL){ //若数据不合法,释放已申请空间,然后返回
delete temp;
DestroyFamilytree();
return result;
}
parentT=0;
Find(T,parentT,parentname); //找到parentname所在结点parentT
if(parentT){ //如果parentT存在,说明parentname在家谱中
//并且parentname为temp的父亲
int cmp;
cmp=CompareDate(temp->info.birthday,parentT->info.birthday);
if(cmp<0){ //若孩子出生日期比父亲大,则不对
delete temp;
DestroyFamilytree();
return FILE_DATA_NOT_PRACTICAL;
}
temp->child=temp->sibling=0;
temp->parent=parentT; //temp的父指针指向parentT;
if(parentT->child){ //parentname已经有孩子
InsertSibling(parentT->child,temp);
}//if
else //parentname无孩子,则temp应为
parentT->child=temp; //parentname的第一个孩子
}//if
else{ //parentT不存在,说明家谱中不存在parentname此人
DestroyFamilytree(); //返回出错信息
return FILE_DATA_ERROR;
}
temp=new PersonNode; //申请一结点
if(!temp){ //申请失败
DestroyFamilytree(); //释放申请空间
return NOT_ENOUGH_MEMORY;
}
result=ReadNode(fp,temp,parentname); //继续读取数据
}//while
if(temp)
delete temp;
fclose(fp);
return OK;
}
void COperationFamilytree::Find(Person& T,Person& Tname,char* name)
{
//本函数以T为根结点开始,搜索结点信息中名字等于name的结点
if(T){ //如果T存在
if(strcmp(T->info.name,name)==0) //T结点姓名和name相同,把T结点指针传给Tname
Tname=T;
else{
Find(T->sibling,Tname,name); //对T的兄弟递归搜索
Find(T->child,Tname,name); //对T的孩子递归搜索
}
}
}
void COperationFamilytree::Find(Person &T, Person*& Tname,int month, int day)
{
//本函数以T为根结点开始,搜索结点信息中生日等于month,day的结点,
//并把所有符合条件的结点指针值存入以Tname为起始地址的地址数组中
if(T){ //如果T存在
if(T->info.birthday.month==month&&T->info.birthday.day==day){
//T结点生日与所给相同,把T结点指针传给Tname,同时Tname指针前进
Person temp;
temp=new PersonNode;
temp=T;
if(temp->info.birthday.month==month&&temp->info.birthday.day==day)
{
*Tname=temp;
Tname++;
}
temp=NULL;
}
Find(T->child,Tname,month,day); //对T的孩子递归搜索
Find(T->sibling,Tname,month,day); //对T的兄弟递归搜索
}
}
void COperationFamilytree::PostOrderTraverse(Person &T, void (__cdecl *Visit)(Person &))
{
//本函数对以T为根结点的所有结点后序遍历访问Visit函数
if(T){
PostOrderTraverse(T->child,Visit);
PostOrderTraverse(T->sibling,Visit);
(*Visit)(T);
}
}
void DestroyNode(Person &pNode)
{
//本函数删除一结点
if(pNode){
delete pNode;
pNode=0;
}
}
void COperationFamilytree::DestroyFamilytree()
{
//本函数删除家谱,释放资源
PostOrderTraverse(T,DestroyNode);
}
int COperationFamilytree::SaveFamilytree(CString filename)
{
//本函数保存家谱到文件filename中
FILE* fp;
if((fp=fopen(filename,"w"))==0) //打开文件filename
return WRITE_FILE_ERROR;
PreOrderTraverse(fp,T,SaveNode); //从根结点开始存储家谱数据
//置家谱数据结束标记(一结点的名字与其父结点的名字同为end)
fprintf(fp,"%s %d %d %d %d %s %d %s","end",1999,12,
2,1,"end",1,"end");
fclose(fp);
return OK;
}
void COperationFamilytree::PreOrderTraverse(FILE* fp,Person &T, void (__cdecl *Visit)(FILE* fp,Person &))
{
//本函数把所有以T结点为根结点的结点值存到文件fp中
if(T){
(*Visit)(fp,T);
PreOrderTraverse(fp,T->child,Visit);
PreOrderTraverse(fp,T->sibling,Visit);
}
}
void SaveNode(FILE *fp, Person &pNode)
{
//本函数向文件fp中存取一结点pNode
char ch='\n';
if(pNode){
fprintf(fp,"%s %d %d %d %d %s %d ",pNode->info.name,pNode->info.birthday.year,
pNode->info.birthday.month,pNode->info.birthday.day,pNode->info.marry,
pNode->info.addr,pNode->info.live);
if(pNode->info.live==0)
fprintf(fp," %d %d %d ",pNode->info.deathday.year,pNode->info.deathday.month,
pNode->info.deathday.day);
if(pNode->parent)
fprintf(fp," %s ",pNode->parent->info.name);
else
fprintf(fp," %s","-1");
fprintf(fp," %c",ch);
}
}
int COperationFamilytree::ReadNode(FILE *fp, Person &T,char* parentname)
{
//本函数从文件fp中读取信息到结点T中,并读取结点的父亲名字到字符数组parentname中
//分别读取结点值,为:姓名,出生日期(年,月,日),婚否,地址,健在否,(如过世,还有死亡日期)
fscanf(fp,"%s%d%d%d%d%s%d",T->info.name,&T->info.birthday.year,&T->info.birthday.month,
&T->info.birthday.day,&T->info.marry,T->info.addr,&T->info.live);
if(T->info.live==0)
fscanf(fp,"%d%d%d",&T->info.deathday.year,&T->info.deathday.month,
&T->info.deathday.day);
fscanf(fp,"%s",parentname);
if(!IsDateValid(T->info.birthday)) //出生日期合法性检查
return FILE_DATA_NOT_PRACTICAL;
if(T->info.live==0) //若过世,死亡日期合法性检查
{ if (CompareDate(T->info.birthday,T->info.deathday)!=-1)
return FILE_DATA_NOT_PRACTICAL;
if(!IsDateValid(T->info.deathday))
return FILE_DATA_NOT_PRACTICAL;}
return OK;
}
bool COperationFamilytree::IsDateValid(Date date)
{
//本函数为日期的有效性检查
switch(date.month){
case 1:
case 3:
case 5:
case 7:
case 8:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -