C++实现家谱图`
#include<iostream>
#include<fstrea`#include<stdio.h>
#include<queue>
#include<string.h>
#include<stdlib.h>
using namespace std;
class Node{
public:
char name[6];//姓名
int birth;//出生日期
int marry;//0为未婚
int now;//表示存活情况,0表示活着,日期表示死亡时间
int gene;//代数
Node *fc;
Node *fb;
Node *fa;
Node(){fc=fb=fa=nullptr;}
};
class Tree{
public:
Node *root;
virtual ~Tree(){};
void Destroy(Node *r)
{
root=nullptr;
}
Tree()
{
int lis[50];//父亲的下标,父亲数组
int ls[20];
int num,numx,k;
queue<Node*> q1;
numx=num=k=0;
ifstream fin("test.txt");
fin>>num; //输入结点的个数
for(int i=0;i<num;i++){fin>>lis[i];}//输入一个数组,数组元素为每个结点的父亲的下标,第一个为-1
Node* p =new Node; //根节点
fin>> p->name >> p->birth >> p->marry >> p->now;
root = p;root->gene=1;//定义root的代数为1
Node* fath; Node* q=root;//定义当前父亲,当前上一个结点
q1.push(root);
//求得作为父亲的结点下表ls[i],共numx个
for(int i=1,j=0;i<num;i++) if(lis[i]>j){ls[numx++]=lis[i];j=lis[i];}
for(int i=1;i<num;i++)
{ //从第二个开始
Node* p =new Node; //定义结点,输入数据
fin>> p->name >> p->birth >> p->marry >> p->now;
//找到父亲,入队操作
if(ls[k]==i) {q1.push(p);k++;}
//录入数据时,子代数为父亲加一
if(lis[i]>lis[i-1]){fath=q1.front();q1.pop();fath->fc=p;p->gene=fath->gene+1;p->fa=fath;q=p;} //如果数字变大,则出队找新的fath,改变当前结点//可以添加老爸
else {q->fb=p;p->gene=fath->gene+1;p->fa=fath;q=p;} //如果数字一样,即此时为上个结点的兄弟
}
cout<<"从test.txt中读取信息并成功创建家谱!"<<endl<<endl;
}
};
void shown(Node* m)
{
cout<<m->name<<' '<<m->gene;
if(m->fc!=nullptr) {shown(m->fc);};
if(m->fb!=nullptr)shown(m->fb);
}
void showmain(Node* n,int x,int &m)//输出第x代
{
if(n->gene==x) {cout<<n->name<<' ';m++;}
if(n->fc!=nullptr)showmain(n->fc,x,m);
if(n->fb!=nullptr)showmain(n->fb,x,m);
}
void shownn(Node* p,int x)
{
int l=0;
cout<<"第 "<<x<<" 代的成员如下:"<<endl;
showmain(p,x,l);cout<<endl;
cout<<"总共有 "<<l<<" 人"<<endl;
}
void addchild(Node* p,char a[],int &flag)//给指定名字的父亲添加孩子
{
flag=0;
if(strcmp(p->name,a)==0)
{
flag=1;
Node* pa=p;//保留父亲结点指针
if(p->fc!=nullptr)
{
p=p->fc;
while(p->fb!=nullptr) p=p->fb;
Node*na =new Node;
cout<<"请输入孩子的姓名:";cin>>na->name;
cout<<"请输入孩子的出生日期:";cin>>na->birth;
cout<<"请输入孩子的婚姻状况:";cin>>na->marry;
cout<<"请输入孩子的生命状态:";cin>>na->now;
na->gene=pa->gene+1; na->fa= pa; p->fb=na;
}
else
{
Node*na =new Node;
cout<<"请输入孩子的姓名:";cin>>na->name;
cout<<"请输入孩子的出生日期:";cin>>na->birth;
cout<<"请输入孩子的婚姻状况:";cin>>na->marry;
cout<<"请输入孩子的生命状态:";cin>>na->now;
na->gene=pa->gene+1; na->fa= pa; p->fc=na;
}
}
if(p->fc!=nullptr&&flag==0)addchild(p->fc,a,flag);
if(p->fb!=nullptr&&flag==0)addchild(p->fb,a,flag);
}
void child(Node* p){//获得该指针p的孩子,用于下面输出个人信息
if(p->fc!=nullptr)
{
p=p->fc;
while(p!=nullptr)
{
cout<<p->name<<' ';
p=p->fb;
}
}
else cout<<"无孩子";
}
void person(Node* p,char a[],int &flag)//输出个人信息
{
flag=0;
if(strcmp(p->name,a)==0)
{
flag=1;
if(p->gene==1)
{
cout<<"姓名:"<<p->name<<endl;
cout<<"出生日期:"<<p->birth<<endl;
cout<<"婚姻状况:"<<p->marry<<endl;
cout<<"生命状态:"<<p->now<<endl;
cout<<"父亲的名字:我是祖宗= ="<<endl;
cout<<"该家族里第 "<<p->gene<<" 代"<<endl;
cout<<"他的孩子有:";
child(p);
}
else
{
cout<<"姓名:"<<p->name<<endl;
cout<<"出生日期:"<<p->birth<<endl;
cout<<"婚姻状况:"<<p->marry<<endl;
cout<<"生命状态:"<<p->now<<endl;
cout<<"父亲的名字:"<<p->fa->name<<endl;
cout<<"该家族里第 "<<p->gene<<" 代"<<endl;
cout<<"他的孩子有:";
child(p);
}
cout<<endl;
}
if(p->fc!=nullptr&&flag==0)person(p->fc,a,flag);
if(p->fb!=nullptr&&flag==0)person(p->fb,a,flag);
}
void dele(Node* p,char a[],int &flagdel)//删除某节点及其子代
{
flagdel=0;
if(strcmp(p->name,a)==0)
{
flagdel=1;
if(strcmp(p->fa->fc->name,p->name)==0) {p->fa->fc=p->fb;}
else
{
Node* zan = p->fa->fc;//定义一个临时指针存储当前位置
while(zan->fb!=p)zan=zan->fb;
zan->fb=p->fb;
}
}
if(p->fc!=nullptr&&flagdel==0)dele(p->fc,a,flagdel);
if(p->fb!=nullptr&&flagdel==0)dele(p->fb,a,flagdel);
}
Node* getlock(Node*p,char a[],int &flaglock)//获得指定名字结点的指针
{ flaglock=0;
if(strcmp(p->name,a)==0) {flaglock=1;return p;}
queue<Node*> q2;
if(p->fc!=nullptr) p=p->fc;
while(p!=nullptr||q2.empty()==0)
{
if(p!=nullptr)
{
if(p->fc!=nullptr) q2.push(p->fc); //有孩子则把孩子进队列
if (strcmp(p->name,a)==0) {flaglock=1;return p;} //访问节点本身
p=p->fb; //指向他的兄弟
}
else {p=q2.front();q2.pop();}//若p为空,则pop
}
}
void getship(Node*p,char a[],char b[]){//输出两者关系
int flaglock1=0,flaglock2=0;
Node* p1=getlock(p,a,flaglock1);
Node* p2=getlock(p,b,flaglock2);
if(flaglock1==0) {cout<<a<<" 不是族谱成员!"<<endl;return;};
if(flaglock2==0) {cout<<b<<" 不是族谱成员!"<<endl;return;};
if(p1->gene==p2->gene)
{
if(strcmp(p1->fa->name,p2->fa->name)==0) cout<<"他们是亲兄弟"<<endl; else cout<<"他们是堂兄弟"<<endl;
}
else if (p1->gene-p2->gene==1)
{
if(strcmp(p1->fa->name,p2->name)==0) cout<<b<<" 是 "<<a<<" 的父亲"<<endl;
else{cout<<b<<" 是 "<<a<<" 的叔伯"<<endl;}
}
else if (p1->gene-p2->gene==-1)
{
if(strcmp(p2->fa->name,p1->name)==0) cout<<a<<" 是 "<<b<<" 的父亲"<<endl;
else{cout<<a<<" 是 "<<b<<" 的叔伯"<<endl;}
}
else if (p1->gene-p2->gene==2)
{
if(strcmp(p1->fa->fa->name,p2->name)==0) cout<<b<<" 是 "<<a<<" 的爷爷"<<endl;
else{cout<<a<<" 是 "<<b<<" 的侄孙"<<endl;}
}
else if (p1->gene-p2->gene==-2)
{
if(strcmp(p2->fa->fa->name,p1->name)==0) cout<<a<<" 是 "<<b<<" 的爷爷"<<endl;
else{cout<<b<<" 是 "<<a<<" 的侄孙"<<endl;}
}
else if (p1->gene-p2->gene==3)
{
if(strcmp(p1->fa->fa->fa->name,p2->name)==0) cout<<b<<" 是 "<<a<<" 的太爷爷"<<endl;
else{cout<<a<<" 是 "<<b<<" 的重侄孙"<<endl;}
}
else if (p1->gene-p2->gene==-3)
{
if(strcmp(p2->fa->fa->fa->name,p1->name)==0) cout<<a<<" 是 "<<b<<" 的太爷爷"<<endl;
else{cout<<b<<" 是 "<<a<<" 的重侄孙"<<endl;}
}
else
{
cout<<"这两个人的关系有点久远哦!直接拿祖宗和后辈处理吧!"<<endl;
if(p1->gene<p2->gene)
cout<<a<<" 是 "<<b<<" 的祖宗"<<endl;
else
cout<<b<<" 是 "<<a<<" 的祖宗"<<endl;
}
}
void showall(Node* p){//打印家谱图
cout<<p->name<<endl;
queue<Node*> q2;
int u=0;
int flag1=0;//输出换行前的队列指针数
int flag2=0;//当前队列中指针数目
int fla[10];//记录上一层结点对应的是否有孩子,有孩子记1.否则0
int flb[10];//记录这层
int flag3=1;//记录上一层节点数目,为0时更新
int flag4=0;//记录当前层结点数
if(p->fc!=nullptr) {p=p->fc;fla[0]=1;}
while(p!=nullptr||q2.empty()==0)
{
if(p!=nullptr)
{
if(p->fc!=nullptr) {flb[flag4++]=1;q2.push(p->fc);flag2++;} //有孩子则把孩子进队列
else flb[flag4++]=0;
cout<<p->name<<' ';
if(p->fb==nullptr)
{
cout<<')';
if(flag1==0)
{
cout<<endl;u=0;
for(int k=0;k<flag4;k++)fla[k]=flb[k];flag3=flag4;flag4=0;flag1=flag2-1;
}
else flag1--;
}
p=p->fb;
}//指向他的兄弟
else
{
if(u<flag3&&fla[u]==1) {p=q2.front();q2.pop();flag2--;u++;}
else{cout<<')';u++;}
} //若p为空,则pop
}
}
void change(Node*p ,char a[])//修改某人信息
{
int flaglock=0;
Node* m =getlock(p,a,flaglock);
if(flaglock==1)
{
cout<<"请输入新的信息 名字 生日 marry now:"<<endl;
cout<<"姓名:";cin>>m->name;cout<<endl;
cout<<"出生日期:";cin>>m->birth;cout<<endl;
cout<<"婚姻状况:";cin>>m->marry;cout<<endl;
cout<<"生命状态:";cin>>m->now;cout<<endl;
cout<<"修改完成!"<<endl;
}
else {cout<<"不存在该人!"<<endl;}
}
void view(Node* n,int &m)//遍历家谱,什么也不做
{
if(n!=nullptr) m++;
if(n->fc!=nullptr)view(n->fc,m);
if(n->fb!=nullptr)view(n->fb,m);
}
int personnum(Node* p)//获得总人数
{
int l=0;
view(p,l);
return l;
}
void getfas(Node*p,int m[])
{
//int m[50];//最大人数为50的父亲数组
Node* s[50];//存储指针的数组;
int k=0;//当前指针数组里的指针个数
int num =personnum(p);//结点总数
m[0]=-1;s[k++]=p;//
queue<Node*> q2;
if(p->fc!=nullptr) {p=p->fc;}
while(p!=nullptr||q2.empty()==0)
{
if(p!=nullptr) {
for(int f=0;f<k;f++)
if(p->fa==s[f]) {m[k]=f;break;}//录入父亲数组
s[k++]=p;//lu入指针数组
if(p->fc!=nullptr) {q2.push(p->fc);} //有孩子则把孩子进队列
p=p->fb;
}
else {p=q2.front();q2.pop();} //若p为空,则pop
}
}
void outdata(Node*p)//输出具体信息到屏幕
{
queue<Node*> q2;
cout<< p->name <<' '<< p->birth<<' ' << p->marry<<' ' << p->now<<endl;
if(p->fc!=nullptr) {p=p->fc;}
while(p!=nullptr||q2.empty()==0)
{
if(p!=nullptr)
{
cout<< p->name <<' '<< p->birth<<' ' << p->marry<<' ' << p->now<<endl;
if(p->fc!=nullptr) {q2.push(p->fc);} //有孩子则把孩子进队列
p=p->fb;
}
else {p=q2.front();q2.pop();} //若p为空,则pop
}
}
void outfile(Node* p)
{
//输出符号和父亲数组
int m[50];
ofstream fout;
fout.open("test.txt");
getfas(p,m);
int v=personnum(p);
fout<<v<<endl;
if(p->fc==nullptr)
{
fout<<'-'<<'1'<<endl;
fout<<p->name <<' '<< p->birth<<' ' << p->marry<<' ' << p->now<<endl;
}
else
{
for(int g=0;g<v;g++)
fout<<m[g]<<' ';
fout<<endl;
//输出具体信息
queue<Node*> q2;
fout<< p->name <<' '<< p->birth<<' ' << p->marry<<' ' << p->now<<endl;
if(p->fc!=nullptr) {p=p->fc;}
while(p!=nullptr||q2.empty()==0)
{
if(p!=nullptr)
{
fout<< p->name <<' '<< p->birth<<' ' << p->marry<<' ' << p->now<<endl;
if(p->fc!=nullptr) {q2.push(p->fc);} //有孩子则把孩子进队列
p=p->fb;
}
else {p=q2.front();q2.pop();} //若p为空,则pop
}
}
fout.close();
}
int main ()
{
Tree c;
/*int m[50];
getfas(c.root,m);
int v=personnum(c.root);
cout<<v<<endl;
for(int g=0;g<v;g++)
cout<<m[g]<<' ';*/
//showall(c.root);
//shown(c.root);
//shownn(c.root,3);//输出第3代
//char a[5];
//char b[5];
//cout<<"输入名字A"<<endl;
//cin>>a;
// cout<<"输入名字B"<<endl;
//cin>>b;
//cout<<"start"<<endl ;
//person(c.root,a);
//child(c.root);
//dele(c.root,a);
//addchild(c.root,a);
//shownn(c.root,3);//输出第3代
//cout<<"????"<<endl;
//getship(c.root,a,b);
//Node *u=getlock(c.root,a);
//cout<<"nice"<<endl;
//cout<<u->name<<endl;
//change(c.root,a);
//cout<<personnum(c.root);
//outfile(c.root);
cout<<"=================================="<<endl;
cout<<"|Welcome To Use Genealogy System |"<<endl;
cout<<"=================================="<<endl;
cout<<endl;
int n,flag3=0,flag4=0,flag5=0,flag6=0,flaglock=0;
char a[8];
char b[8];
while(n!=0)
{
cout<<"1.显示家谱图"<<endl;
cout<<"2.查找第m代人数及名字"<<endl;
cout<<"3.姓名查询个人信息"<<endl;
cout<<"4.输入两人姓名,确认关系"<<endl;
cout<<"5.给某人添加孩子"<<endl;
cout<<"6.删除某人"<<endl;
cout<<"7.修改某人信息"<<endl;
cout<<"8.输出到test.txt文件"<<endl;
cout<<"9.输出所有人信息"<<endl;
cout<<"0.退出"<<endl;
cout<<"请输入n,进入功能模块"<<endl;
cin>>n;
switch(n){
case 1: cout<<"-------------显示家谱图-------------"<<endl;
if(c.root==nullptr)
cout<<"家谱为空!"<<endl;
else if(c.root->fc==nullptr)
cout<<c.root->name<<endl;
else
showall(c.root);
cout<<"------------------------------------"<<endl;break;
case 2: cout<<"---------查找第m代人数及名字--------"<<endl;
int m;cout<<"请输入代数m:";cin >>m;cout<<endl;
shownn(c.root,m);
cout<<"------------------------------------"<<endl;break;
case 3: cout<<"----------姓名查询个人信息----------"<<endl;
cout<<"请输入姓名: "<<endl;cin>>a;
person(c.root,a,flag3);
if(flag3==0)
cout<<"不存在该人!"<<endl;
cout<<"------------------------------------"<<endl;break;
case 4: cout<<"-------输入两人姓名,确认关系-------"<<endl;
cout<<"请输入第一人的姓名:";cin>>a;cout<<endl;
cout<<"请输入第二人的姓名:";cin>>b;cout<<endl;
getship(c.root,a,b);
cout<<"------------------------------------"<<endl;break;
case 5: cout<<"-----------给某人添加孩子-----------"<<endl;
cout<<"请输入孩子的父亲的名字:";cin>>a;cout<<endl;
addchild(c.root,a,flag5);
if(flag5==1)
cout<<"添加孩子完成!"<<endl;
else
cout<<"不存在该人,无法添加孩子!"<<endl;
cout<<"------------------------------------"<<endl;break;
case 6: cout<<"--------------删除某人--------------"<<endl;
cout<<"请输入姓名:";cin>>a;cout<<endl;
if(strcmp(a,c.root->name)==0)
{c.Destroy(c.root);flag6=1;}
else
dele(c.root,a,flag6);
if(flag6==0)
cout<<"不存在该人,删除失败!"<<endl;
else
cout<<"删除成功!"<<endl;
cout<<"------------------------------------"<<endl;break;
case 7: cout<<"------------修改某人信息------------"<<endl;
cout<<"请输入被修改人的姓名:";cin>>a;cout<<endl;
change(c.root,a);
cout<<"------------------------------------"<<endl;break;
case 8: cout<<"---------输出到原test.txt文件--------"<<endl;
if(c.root==nullptr)
{cout<<"家谱为空!"<<endl;cout<<"输出失败!"<<endl;}
else
{outfile(c.root);cout<<"输出成功!"<<endl;}
cout<<"------------------------------------"<<endl;break;
case 9: cout<<"-----------输出所有人信息-----------"<<endl;
if(c.root==nullptr)
cout<<"家谱为空!"<<endl;
else
outdata(c.root);
cout<<"------------------------------------"<<endl;break;
}
cout<<endl;
}
return 0;
}
------------------------test.txt
9
-1 0 0 2 2 2 4 4 6
jack 1940 1 2020
kara 1963 1 0
kim 1970 1 2017
an 1982 0 0
mona 1985 1 0
sunny 1879 1 0
kaka 1999 1 0
cindy 2001 0 0
rain 2009 0 0
文档说明:看main函数即可,show部分为双亲表示法。