家族关系查询系统
1.问题描述
建立家族关系数据库,实现对家族成员关系的相关查询。
2.基本要求
(1)建立家族关系并能存储到文件中;
(2)实现家族成员的添加。
(3)可以查询家族成员的双亲、祖先、兄弟、孩子和后代等信息。
3.扩展功能
在家族关系查询中包含了许多查询功能,可通过输入不同的命令和参数有选择的实现各种查询。在编写程序时,可以加入修改成员信息的功能并能及时更新保存。
数据结构的课程设计,用的三叉树,STL中的queue,使用文件形式输入。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define MAX 20
typedef struct TriTNode
{
char data[MAX];
struct TriTNode *parent;//双亲
struct TriTNode *lchild;
struct TriTNode *rchild;
} Tree,*TreePt;
char fname[MAX],family[50][MAX];// 全局变量
Tree *Open(char familyname[MAX]);
Tree *TreeCreate();
Tree *Search(Tree *t,char str[]);
void Append(Tree *t);
void Ancestor(Tree *t);
void AncestorPath(Tree *t);
void Parent(Tree *t);
void Generation(Tree *t);
void Brothers(Tree *t,char str[]);
void Consin(Tree *t);
void Children(Tree *t);
void InOrder(Tree *t);
void allChildren(Tree *t);
Tree *Create(char familyname[MAX]);
int main()
{
char str[MAX];
int flag,start =0;;
Tree *temp,*tree=NULL;
while(1)
{
printf("\t欢迎使用家族关系查询系统!\n");
printf("\t 1.新建一个家庭关系:\n");
printf("\t 2.打开一个家庭关系: \n");
printf("\t 3.添加新成员的信息: \n");
printf("\t 4.查找家族的祖先:\n");
printf("\t 5.查找一个成员的祖先路径:\n");
printf("\t 6.确定一个成员是第几代:\n");
printf("\t 7.查找一个成员的双亲:\n");
printf("\t 8.查找一个成员的兄弟:\n");
printf("\t 9.查找一个成员的堂兄弟:\n");
printf("\t10.查找一个成员的孩子:\n");
printf("\t11.查找一个成员的子孙后代:\n");
printf("\t12.退出系统: \n ");
cin>>flag;
if(!(flag==1||flag==2||flag==12)&&start==0)
{
printf("请先建立或打开一个家族关系!\n");
continue;
}
start=1;
switch(flag) //根据flag标记调用函数
{
case 1:
cout<<"请输入家族名氏"<>str;
temp=Search(tree,str);
if(!temp) // 若不存在则返回
{
printf("该成员不存在!\n");
continue;
}
AncestorPath(temp);
break;
case 6:
cout<<"请输入成员名氏"<>str;
temp=Search(tree,str);
if(!temp) // 若不存在则返回
{
printf("该成员不存在!\n");
continue;
}
Generation(temp);
break;
case 7:
cout<<"请输入成员名氏"<>str;
temp=Search(tree,str);
if(!temp) // 若不存在则返回
{
printf("该成员不存在!\n");
continue;
}
Parent(temp);
break;
case 8:
cout<<"请输入成员名氏"<>str;
temp=Search(tree,str);
if(!temp) // 若不存在则返回
{
printf("该成员不存在!\n");
continue;
}
Brothers(temp,str);
break;
case 9:
cout<<"请输入成员名氏"<>str;
temp=Search(tree,str);
if(!temp) // 若不存在则返回
{
printf("该成员不存在!\n");
continue;
}
Consin(temp);
break;
case 10:
cout<<"请输入成员名氏"<>str;
temp=Search(tree,str);
if(!temp) // 若不存在则返回
{
printf("该成员不存在!\n");
continue;
}
Children(temp);
break;
case 11:
cout<<"请输入成员名氏"<>str;
temp=Search(tree,str);
if(!temp) // 若不存在则返回
{
printf("该成员不存在!\n");
continue;
}
allChildren(temp);
break;
case 12:
exit(1);
}
}
return 0;
}
Tree *Create(char familyname[MAX])//建立家族关系并存入文件
{
int i=0;
char ch,str[MAX]; //
Tree *t;
FILE *fp;
strcpy(fname,familyname); //以家族名为文本文件名存储
strcat(fname,".txt");
fp=fopen(fname,"r"); //以读取方式打开文件
if(fp) // 文件已存在
{
fclose(fp);
printf("%s 的家族关系已存在!重新建立请按“Y”,直接打开请按“N”\n",familyname);
ch=getchar();
getchar();
if(ch=='N'||ch=='n')
{
t=Open(familyname);// 直接打开
return t;
}
}
if(!fp||ch=='Y'||ch=='y') //重新建立,执行以下操作
{
fp=fopen(fname,"w"); //以写入方式打开文件,不存在则新建
printf("请按层次输入结点,每个结点信息占一行\n");
printf("兄弟输入结束以“@”为标志,结束标志为“#”\n★");
gets(str);
fputs(str,fp);
fputc('\n',fp);
strcpy(family[i],str); //将成员信息存储到字符数组中*/
i++;
while(str[0]!='#')
{
printf("★"); //提示符提示继续输入
gets(str);
fputs(str,fp); //写到文件中,每个信息占一行
fputc('\n',fp);
strcpy(family[i],str); //将成员信息存储到字符数组中
i++;
}
fclose(fp);
t=TreeCreate(); // 根据family数组信息创建三叉树*/
printf("家族关系已成功建立!\n");
return t;
}
return 0;
}
Tree *TreeCreate()
{
Tree *t,*tree,*root=NULL;
queueq;
int i=0,flag=0,start=0;
char str[MAX]; // 存放family数组中信息
strcpy(str,family[i]);
i++;
while(str[0]!='#') //没遇到结束标志继续循环*/
{
while(str[0]!='@') //没遇到兄弟输入结束标志继续
{
if(root==NULL) // 空树
{
root=(Tree *)malloc(sizeof(Tree));
strcpy(root->data,str);
root->parent=NULL;
root->lchild=NULL;
root->rchild=NULL;
q.push(root);
tree=root;
}
else //不为空树
{
t=(Tree *)malloc(sizeof(Tree));
strcpy(t->data,str);
t->lchild=NULL;
t->rchild=NULL;
t->parent = q.front();// 当前结点的双亲为队头元素
q.push(t);
if(flag == 0) //flag为0,当前结点没有左孩子
root->lchild=t;
else
root->rchild=t; //flag为1,当前结点已有左孩子
root=t; //root指向新的结点t
}
flag=1; //标记当前结点已有左孩子
strcpy(str,family[i]);
i++;
}
if(start!=0) //标记不是第一次出现“@”
{
q.pop();
if(q.front())
root = q.front();
}
start=1; // 标记已出现过“@”
flag=0; //“@”后面的结点一定为左孩子
strcpy(str,family[i]);
i++;
}
return tree;
}
Tree *Open(char familyname[MAX])
{
int i=0,j=0;
char ch;
FILE *fp;
Tree *t;
strcpy(fname,familyname); //以家族名为文本文件名存储
strcat(fname,".txt");
fp=fopen(fname,"r"); //以读取方式打开文件
if(fp==NULL) //文件不存在
{
printf("%s 的家族关系不存在!\n",familyname);
return NULL;
}
else
{
ch=fgetc(fp); //按字符读取文件
while(ch!=EOF) //读到文件尾结束
{
if(ch!='\n')
{
family[i][j]=ch;
j++;
}
else
{
family[i][j]='\0'; //字符串结束标志
i++; //family数组行下标后移
j=0; //family数组列下标归零
}
ch=fgetc(fp); //继续读取文件信息
}
fclose(fp);
t=TreeCreate(); //调用函数建立三叉链表
printf("家族关系已成功打开!\n");
return t;
}
}
Tree *Search(Tree *t,char str[])
{
Tree *temp;
if(t==NULL) //如果树空则返回NULL
return NULL;
else if(strcmp(t->data,str)==0) //如果找到返回该成员指针
return t;
else //如果没找到遍历左右子树进行查找
{
temp=Search(t->lchild,str);
if(temp) //结点不空则查找
return(Search(t->lchild,str));
else
return(Search(t->rchild,str));
}
}
void Append(Tree *t) //添加成员
{
int i=0,j,parpos=1,curpos,num,end=0,count=-1;
char chi[MAX],par[MAX]; //存储输入的孩子和其双亲结点
Tree *tpar,*temp;
FILE *fp;
printf("请输入要添加的成员和其父亲,以回车分隔!\n. ");
getchar();
gets(chi);
printf(". "); //以点提示符提示继续输入
gets(par);
tpar=Search(t,par); //查找双亲结点是否存在
if(!tpar)
printf("%s 该成员不存在!\n",par);
else //存在则添加其孩子
{
temp=(Tree *)malloc(sizeof(Tree));
temp->parent=tpar;
strcpy(temp->data,chi);
temp->lchild=NULL;
temp->rchild=NULL;
if(tpar->lchild) //成员存在左孩子
{
tpar=tpar->lchild; //遍历当前成员左孩子的右子树
while(tpar->rchild) //当前结点右孩子存在
tpar=tpar->rchild; //继续遍历右孩子
tpar->rchild=temp; //将新结点添加到所有孩子之后*/
}
else //没有孩子则直接添加
tpar->lchild=temp;
fp=fopen(fname,"w"); // 以写入方式打开文件
if(fp)
{
while(strcmp(par,family[i])!=0&&family[i][0]!='#')
{
if(family[i][0]!='@')
parpos++;
i++;
}
i=0;
while(family[i][0]!='#')
{
if(family[i][0]=='@')
count++;
if(count==parpos)
curpos=i;
i++;
}
if(count=curpos; j--)
strcpy(family[j+1],family[j]);
strcpy(family[curpos],chi);
}
if(end==1)
i=i+num;
for(j=0; j<=i+1; j++)
{
fputs(family[j],fp);
fputc('\n',fp);
}
fclose(fp);
cout<<"添加新成员成功!"<data);
}
void AncestorPath(Tree *t) //祖先路径
{
if(t->parent==NULL) //若该成员为祖先,则直接输出
printf("%s 无祖先!\n",t->data);
else
{
printf("%s 所有祖先路径:%s",t->data,t->data);
while(t->parent!=NULL) //若当前成员的双亲不是祖先,则继续查找
{
printf(" --> %s",t->parent->data); //访问当前成员的双亲
t=t->parent;
}
printf("\n");
}
}
void Parent(Tree *t) //双亲
{
if(t->parent!=NULL) //若该成员为祖先,则无双亲
printf("%s 的双亲为%s\n",t->data,t->parent->data);
else
printf("%s 无双亲!\n",t->data);
}
void Generation(Tree *t) //确定一个成员是第几代
{
int count=1;
char str[MAX];
strcpy(str,t->data);
while(t->parent!=NULL)
{
count++;
t=t->parent;
}
printf("%s 是第%d 代!\n",str,count);
}
void Brothers(Tree *t,char str[]) //查找兄弟
{
if(t->parent!=NULL) //若该结点是祖先,则无兄弟
{
t=t->parent; //该结点的兄弟即为其双亲除该成员以外的所有孩子
if(t->lchild&&t->lchild->rchild) //当前结点的左孩子及其右孩子都存在
{
printf("%s 的所有兄弟有:",str);
t=t->lchild;
while(t) //遍历当前成员左孩子的右子树
{
if(strcmp(t->data,str)!=0) //遍历右子树,选择输出
printf("%s ",t->data); //访问当前结点
t=t->rchild;
}
printf("\n");
}
else
printf("%s 无兄弟!\n",str);
}
else
printf("%s 无兄弟!\n",str);
}
void Consin(Tree *t)
{
int flag=0;
Tree *ch=t;
Tree *temp;
if(t->parent&&t->parent->parent)//当前结点的双亲及其双亲都存在
{
t=t->parent->parent->lchild;//当前结点等于其祖先的第一个孩子
while(t) //存在则继续查找
{
if(strcmp(t->data,ch->parent->data)!=0)
{
if(t->lchild) //当前结点存在左孩子*/
{
temp=t->lchild;
while(temp) //遍历当前结点左孩子的右子树*/
{
if(strcmp(temp->data,ch->data)!=0)
{
if(!flag)
printf("%s 的所有堂兄弟有:",ch->data);
printf("%s ",temp->data);
flag=1;
}
temp=temp->rchild; //继续遍历右孩子
}
}
}
t=t->rchild; //继续遍历右孩子
}
printf("\n");
}
if(!flag)
printf("%s 无堂兄弟!\n",ch->data);
}
void Children(Tree *t) //遍历左孩子
{
if(t->lchild) // 当前结点存在左孩子
{
printf("%s 的所有孩子有:",t->data);
t=t->lchild; //遍历当前成员左孩子的右子树*/
while(t)
{
printf("%s ",t->data);
t=t->rchild;
}
printf("\n");
}
else
printf("%s 无孩子!\n",t->data);
}
/* 中序遍历一棵树*/
void InOrder(Tree *t)
{
if(t)
{
InOrder(t->lchild);
printf("%s ",t->data);
InOrder(t->rchild);
}
}
void allChildren(Tree *t) //所有后代
{
if(t->lchild) //当前结点存在左孩子
{
printf("%s 的所有子孙后代有:",t->data);
InOrder(t->lchild); //中序遍历当前结点的左右子树
printf("\n");
}
else
printf("%s 无后代!\n",t->data);
}