family.cpp
/***********************************************************
*版权所有(C)2017,
*
*文件名称:family.cpp
*文件标识:无
*内容摘要:该部分代码用于自定义函数说明
*其它说明:无
*当前版本:V1.0
*作 者:于子淇
*完成日期:2017.12.21
*
*版本号:V1.0
**********************************************************/
#include "head.h"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <conio.h>
void display0();
using namespace std;
/*********************************************************
*功能描述:容错保障
*输入参数:x
*输出参数:无
*返回值:x-成功/其他-失败
*其它说明:消息字段之间用分号(;)分隔
throw抛出异常,即检测是否产生异常,如果在try语句块的程序段中(包括在其中调用的函数)发现了异常,且抛弃了该异常,则这个异常就可以被try语句块后的某个catch语句所捕获并处理,捕获和处理的条件是被抛弃的异常类型与catch语句的异常类型相匹配。
***********************************************************/
template<class T>//模板
T fun(T x)
{
if(x!=2)
throw x;
else
return x;
}
treenode *root; //root是指向结构体treenode的指针
/*********************************************************
*功能描述:遍历家谱树各个结点返回指向所要查找的成员结点指针(或没找到返回NULL)
*输入参数: *p 头指针用来指向头结点(*root)or递归过程的其他结点(兄弟结点或孩子结点)
ch[]用来储存姓名(所查找的成员姓名)
*输出参数:无
*返回值:*q or NULL
*其它说明:消息字段之间用分号(;)分隔
通过递归函数在兄弟、孩子中查找
***********************************************************/
treenode *search(treenode *p,char ch[]) // 搜索指针函数,搜索需要修改和获得的结点,输入头指针,姓名
{
treenode *q;
if(p==NULL) return NULL;//没有家谱,头指针下为空
if(strcmpi(p->l.name,ch)==0)//比较姓名,看是否重名或是否存在
return p;//家谱不为空,头指针下有这个人
if(p->brother)
{
//递归过程
q=search(p->brother,ch);//在兄弟中找
if(q)
return q;//找到
}
if(p->child)
{
q=search(p->child,ch);//在孩子中找
if(q!=NULL)
return q; //找到则返回指针q
}
return NULL;//没有找到
}
/*********************************************************
*功能描述:获得搜索到的成员的第几代并返回其代的数据信息
*输入参数: *p 头指针用来指向头结点(*root)or递归过程的其他结点(兄弟结点或孩子结点)
ch[]用来储存姓名
*输出参数:被查找人的代的数据信息
*返回值:q->l.generation or 0
*其它说明:消息字段之间用分号(;)分隔
通过递归在兄弟、孩子中查找
***********************************************************/
int generation(treenode *p,char ch[]) //获得搜索到的成员的代的返回值
{
treenode *q;
if(p==NULL)
return 0;
if(strcmpi(p->l.name,ch)==0) //比较姓名,看是否重名或是否存在
return p->l.generation;//家谱不为空,头指针下有这个人
if(p->brother)
{
q=search(p->brother,ch);//在兄弟中找
if(q)
return q->l.generation;//找到
}
if(p->child)
{
q=search(p->child,ch);//在孩子中找
if(q!=NULL)
return q->l.generation; //找到
}
return 0;
}
/*********************************************************
*功能描述:建立家谱孩子结点,创建结点并对l赋值保存
*输入参数: *p 头指针用来指向结点 b[] 孩子名字 c 性别
*输出参数:无
*返回值:无
*其它说明:消息字段之间用分号(;)分隔
***********************************************************/
void children(treenode *p,char b[],char c,int d)//建立家谱孩子结点,创建结点并对l赋值保存
{
int i;
for(i=0;i<MAX;i++)
p->l.name[i]=b[i];
p->l.sex=c;
p->l.generation=d;
}
/*********************************************************
*功能描述:输出成员信息
*输入参数: *n 结点,是之前search()函数返回的指向所查找的成员的指针,在此作为输入
*输出参数:l.name 姓名 l.sex 性别 l.generation 第几代
以及该查找成员的兄弟(父母未实现)
*返回值:无
*其它说明:消息字段之间用分号(;)分隔
***********************************************************/
void output(treenode *n) //搜索到数据的输出
{
treenode *t=NULL;
printf("此人姓名:%s 性别%c 为第%d代\n",n->l.name,n->l.sex,n->l.generation);
printf("\n");
printf("此人的子女:"); //子女输出
if(n->child==NULL)//当该结点的孩子指针域为空时,代表此人没有孩子
{
printf("此人无子女!");
}
else//有孩子
{
if(n->child->brother==NULL)//孩子无兄弟
{
printf("姓名:%s 性别:%c\t",n->child->l.name,n->child->l.sex);//就只输出孩子的数据信息
}
else//当孩子有兄弟时(原父辈不止一个孩子)
{
printf("姓名:%s 性别:%c\t",n->child->l.name,n->child->l.sex);//输出完第一个孩子后再将指针n->child->brother赋给指针t
t=n->child->brother;
while(t!=NULL)//当t指针存在时(直到输出完最后一个孩子)
{
printf("姓名:%s 性别:%c\t",t->l.name,t->l.sex);//输出其他孩子的姓名
t=t->brother;//将指针再指向兄弟的兄弟
}
}
}
printf("\n");
printf("此人的同辈成员:"); //同辈输出
if(n->brother==NULL)
{
printf("此人无同辈成员!");
}
else
{
if(n->brother->brother==NULL)
{
printf("姓名:%s 性别:%c\t",n->brother->l.name,n->brother->l.sex);
}
else
{
printf("姓名:%s 性别:%c\t",n->brother->l.name,n->brother->l.sex);
t=n->brother->brother;
while(t!=NULL)
{
printf("姓名:%s 性别:%c\t",t->l.name,t->l.sex);
t=t->brother;
}
}
}
}
/*********************************************************
*功能描述:初始化家谱
*输入参数: 输入始祖姓名、性别
并记录始祖的generation为第1代
*输出参数:无
*其它说明:消息字段之间用分号(;)分隔
先释放root内存空间,再为root创建内存空间储存结点
***********************************************************/
void InitTree() //初始化(创建)
{
system("cls");
//system("color 4f");
cout<<endl<<endl<<endl<<endl;
cout<<" ********************************************"<<endl;
cout<<" * *"<<endl;
cout<<" * 现在开始初始化家族族谱 *"<<endl;
cout<<" * *"<<endl;
cout<<" ********************************************"<<endl;
cout<<endl<<endl<<endl;
int a;
char b[MAX],c;
printf(" 请输入始祖的姓名性别:");
free(root);//释放root (ft)空间
root=(treenode *)malloc(sizeof(treenode)); // 创建一个treenode结构体大小的空间
//然后强制转换为treenode *类型的指针然后赋值给root
scanf("%s %c",&b,&c);//输入姓名,性别
while(c!='m'&&c!='f')
{
try
{
fun(c);
}
catch(...)
{
cout<<"输入性别有误!请重新输入!(女士f男士m):"<<endl;
}
scanf("%s %c",&b,&c);//输入姓名,性别
}
a=1;//定义该祖先为第一代人
root->child=NULL; //清空左右孩子
root->brother=NULL;
children(root,b,c,a);//存入结构
printf("家谱初始化成功!\n");
/*printf("\n按任意键返回主菜单..\n");
getchar();*/
system("pause");
system("cls");
display0();
}
/*********************************************************
*功能描述:添加成员信息
*输入参数:成员的数据信息 b[]子辈姓名 c 性别 d[] 父辈姓名
*返回值:无
*其它说明:消息字段之间用分号(;)分隔
通过查找上一辈家长的位置添加其子女的信息(符合显示中添加子女信息的需求)
对于家谱中是否存在此人用上面代码中search()判断
容错包括:重名容错与性别容错
***********************************************************/
void Add() //添加
{
system("cls");
//system("color 4f");
int a;
cout<<endl<<endl<<endl<<endl;
cout<<" ********************************************"<<endl;
cout<<" * *"<<endl;
cout<<" * 现在开始添加家庭成员操作 *"<<endl;
cout<<" * *"<<endl;
cout<<" ********************************************"<<endl;
cout<<endl<<endl<<endl;
treenode *n,*m,*t=NULL;
char b[MAX],c,d[MAX];
printf("请输入要添加子女的上一辈的姓名:");
scanf("%s",&d);
n=search(root,d);
a=generation(root,d);
while(n==NULL) //判断是否有重名
{
printf("此人不在家谱内,请重新输入姓名:");
scanf("%s",&d);
n=search(root,d);
}
if(n->child==NULL)//孩子信息添加,当满足该父辈无子女时,进入条件判断
{
printf(" 请输入所添加家庭成员的姓名与性别(注意不能重名):");
scanf("%s %c",&b,&c);
while(c!='m'&&c!='f')
{
try
{
fun(c);
}
catch(...)
{
cout<<"输入性别有误!请重新输入!(女士f男士m):"<<endl;
}
scanf("%s %c",&b,&c);//输入姓名,性别
}
a++;//此处a代表孩子的辈分
m=search(root,b);//搜索族谱之中是否有与新添加成员重名的人,若有则添加失败
if(m!=NULL)
{
printf("出现重名,添加失败!\n");
}
else
{
n->child=(treenode *)malloc(sizeof(treenode));
n->child->brother=NULL;
n->child->child=NULL;
children(n->child,b,c,a);
printf("添加成功!\n");
}
}
else//当该父辈之前已经有子女的时候,则此新添加的成员为添加的前一个孩子的兄弟
{
n=n->child;
while(n->brother!=NULL) //添加另一个孩子
n=n->brother;
printf("请输入所添加家庭成员的姓名与性别(注意不能重名):");
scanf("%s %c",&b,&c);
while(c!='m'&&c!='f')
{
try
{
fun(c);
}
catch(...)
{
cout<<"输入性别有误!请重新输入!(女士f男士m):"<<endl;
}
scanf("%s %c",&b,&c);//输入姓名,性别
}
a++;
m=search(root,b);
if(m!=NULL)
printf("出现重名,添加失败!\n");
else
{
t=(treenode *)malloc(sizeof(treenode));
children(t,b,c,a);
t->brother=NULL;
t->child=NULL;
n->brother=t;
printf("添加成功!\n");
}
}
printf("\n按任意键返回主菜单..\n");
getch();
system("cls");
display0();
}
/*********************************************************
*功能描述:查找功能的实现
*输入参数:d[] 姓名
*返回值:无
*输出参数:输出被查找人的信息
*其它说明:消息字段之间用分号(;)分隔
该函数与search()函数和output()函数共同构成查询模块
***********************************************************/
void Search() //查找
{
treenode *n;
char d[MAX];
printf("输入姓名,查找相关信息:");
scanf("%s",&d);
n=search(root,d);
while(n==NULL)
{
printf("此人不存在,请再次输入:");
scanf("%s",&d);
n=search(root,d);
}
output(n);
printf("\n");
printf("\n按任意键返回主菜单..\n");
getch();
system("cls");
display0();
}
/*********************************************************
*功能描述:修改成员信息
*输入参数: 要修改人的姓名(判断此人是否存在)
*输出参数:存在则输出此人的数据信息,不存在则重新输入
*返回值:无
*其它说明:消息字段之间用分号(;)分隔
修改成员函数中同样做了性别容错,修改的过程只是将其数据进行覆盖的过程,并不会影响该结点的孩子结点与兄弟结点的指向。
***********************************************************/
void Change() //修改
{
char a[MAX],r[MAX],c;
treenode *n;
int i;
printf("请输入要修改人的姓名:");
scanf("%s",&a);
n=search(root,a);
while(n==NULL)
{
printf("此人不存在,请重新输入姓名:");
scanf("%s",&a);
n=search(root,a);
}
printf("此人存在,请输入新信息:");
scanf("%s %c",&r,&c);
while(c!='m'&&c!='f')//性别容错
{
try
{
fun(c);
}
catch(...)
{
cout<<"输入性别有误!请重新输入!(女士f男士m):"<<endl;
}
scanf("%s %c",&r,&c);//输入姓名,性别
}
for(i=0;i<MAX;i++)
n->l.name[i]=r[i];
n->l.sex=c;
printf("修改成功!\n");
printf("\n按任意键返回主菜单..\n");
getch();
system("cls");
display0();
}
/*********************************************************
*功能描述:显示模块
*输入参数:数字选项
*输出参数:跳转其他操作界面
*其它说明:消息字段之间用分号(;)分隔
数字选项输入容错保障
***********************************************************/
void display0()//最初显示界面
{
system("cls");
//system("color 4f");
cout<<endl;
cout<<" ** ** ********* ** ** *** "<<endl;
cout<<" ** ** ********* ** ** ** ** "<<endl;
cout<<" ** ** ** ** ** ** ** "<<endl;
cout<<" ** ** ** ** ** ** ** "<<endl;
cout<<" ********* ********* ** ** ** ** "<<endl;
cout<<" ********* ********* ** ** ** ** "<<endl;
cout<<" ** ** ** ** ** ** ** "<<endl;
cout<<" ** ** ** ** ** ** ** "<<endl;
cout<<" ** ** ********* ********* ********* ** ** "<<endl;
cout<<" ** ** ********* ********* ********* *** "<<endl;
cout<<endl;
cout<<" **************************************"<<endl;
cout<<" * *"<<endl;
cout<<" * 欢迎进入家谱管理系统 *"<<endl;
cout<<" * *"<<endl;
cout<<" **************************************"<<endl;
cout<<endl<<endl;
cout<<" 1 添加成员"<<endl<<endl;
cout<<" 2 查询个人信息"<<endl<<endl;
cout<<" 3 修改信息"<<endl<<endl;
cout<<" 4 创建族谱"<<endl<<endl;
cout<<" 5 退出"<<endl<<endl;
cout<<endl;
int a;
cout<<" 请输入数字:";
cin>>a;
while(!cin)
{
cout<<" 输入错误,请重新输入:";
cin.sync();
cin.clear();
cin>>a;
}
while(a<1||a>6)
{
try
{
fun(a);
}
catch(...)
{
cout<<" 输入错误,请重新输入:";
}
cin>>a;
}
switch(a)
{
case 1:
Add();
system("pause");
break;
case 2:
Search();
system("pause");
break;
case 3:
Change();
case 4:
InitTree();
system("pause");
break;
case 5:
exit(0);
break;
}
}
family.h
/***********************************************************
*版权所有(C)2017,
*
*文件名称:family.h
*文件标识:无
*内容摘要:定义树结构体并声明函数
*其它说明:无
*当前版本:V1.0
*作 者:于子淇
*完成日期:2017.12.21
*
*版本号:V1.0
**********************************************************/
#ifndef FAMILY_H_INCLUDED
#define FAMILY_H_INCLUDED
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <stdlib.h>
#define MAX 10
typedef struct info//定义data存储结构,存放个人信息
{ char name[MAX]; //姓名
char sex;//性别
int generation;//代
}info;
typedef info ElemType;//将ElemType定义成结构体类型
typedef struct treenode//创建结构体
{
ElemType l;
struct treenode *brother;//用来指向兄弟
struct treenode *child;//用来指向孩子
}treenode;
treenode *search(treenode *p,char ch[]); // 搜索指针函数,搜索需要修改和获得的结点,输入头指针,姓名
int generation(treenode *p,char ch[]); //获得搜索到的成员的代的返回值
void children(treenode *p,char b[],char c,int d);//建立家谱孩子结点,创建结点并对l赋值保存
void output(treenode *n); //搜索到数据的输出
void InitTree(); //初始化(创建)
void Add(); //添加
void Search(); //查找
void Change(); //修改
#endif // FAMILY_H_INCLUDED
main.cpp
/***********************************************************
*版权所有(C)2017,
*
*文件名称:main.cpp
*文件标识:无
*内容摘要:主函数(显示模块)
*其它说明:无
*当前版本:V1.0
*作 者:于子淇
*完成日期:2017.12.21
*
*版本号:V1.0
**********************************************************/
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include "family.h"
void display0();
using namespace std;
int main()
{
display0();//程序运行后,直接跳转进入显示模块,对功能进行选择
return 0;
}