目录
1、问题描述
家谱管理系统是查询家谱信息必不可少的一部分,利用家谱管理系统可以清楚地查询成员的详细信息。成员的信息包括:姓名(假设姓名不重复)、出生年月日、目前状况(健在、身故)。请设计合理的数据结构存储该家谱的信息,要求能够实现以下功能功能。
2、基本功能
该系统应具有以下功能(即可以重复操作):
家谱信息预先设置好,程序启动,从文件中读入家谱信息,自动建立家谱数据结构,使用菜单实现以下功能,每次操作后应该输出当前结果:
(1)插入:给某个人添加一个孩子
(2)删除:删除某个人,如果某人有后代,不允许删除
(3)堂兄弟:根据所在世代的字,可以输出该世代所有人的信息
(4)父子:可以根据姓名查询,并输出该人的父亲和孩子信息
(5)显示:以凹入表的形式显示家谱
(6)退出时,家谱信息保存到文件中
3、测试数据
通过循环将家谱信息读入家谱树。
#include <stdlib.h>
#include<iostream>
#include<fstream>
#pragma warning(disable:4996)
using namespace std;
typedef struct {
char name[50];//姓名
int brithday;//出生
int beifen;//辈分
int die;//是否健在
}StructNode;
typedef struct Node {
StructNode data;
struct Node* lc;//左指针
struct Node* rc;//右指针
}TreeNode;
int num;//总人数
TreeNode* root;//根指针
TreeNode* findLocation(TreeNode* b, char cname[]) //查询位置
{
TreeNode* p;
if (b == NULL) return NULL;
if (strcmp(b->data.name, cname) == 0)
return b;
if (b->lc) {
p = findLocation(b->lc, cname);
if (p)return p;
}
if (b->rc) {
p = findLocation(b->rc, cname);
if (p)return p;
}
return NULL;
}
void searchByChar(TreeNode* node, char letter) {
if (node == NULL) {
return;
}
string name = node->data.name;
if (name.find(letter) != string::npos) {
cout << "Name: " << node->data.name << endl;
cout << "Birthday: " << node->data.brithday << endl;
cout << "Alive: " << node->data.die << endl;
cout << "----------------" << endl;
}
searchByChar(node->lc, letter);
searchByChar(node->rc, letter);
}
TreeNode* creatFirst()//创建你的祖宗
{
TreeNode* p;
p = new Node;//创建新的节点
cout << "输入祖宗名字:" << endl;
cin >> p->data.name;
cout << "输入祖宗的诞生时间:" << endl;
cin >> p->data.brithday;
cout << "是否存活:" << endl;
cin >> p->data.die;
p->lc = p->rc = NULL;//左右子树清空
p->data.beifen = 1;//当前辈分为1
cout << "祖宗创建成功" << endl;
return p;
}
TreeNode* creatNode()//创建一个新的节点
{
int flag = 0;
TreeNode* m = NULL;//指针初始化
TreeNode* p;
p = new Node;//创建新的节点
cout << "输入名字:" << endl;
cin >> p->data.name;
m = findLocation(root, p->data.name);//查找当前名字返回的变量
if (m != NULL)
{
cout << "出现重名!!!\n";
p = NULL;
return p;
}
else {
cout << "输入诞生时间:" << endl;
cin >> p->data.brithday;
cout << "是否存活:" << endl;
cin >> p->data.die;
return p;
}
}
void cunru(TreeNode* p, char name[], int dai, int brithday, int die)//存入结构体
{
//赋值给结构体
p->data.beifen = dai;
strcpy_s(p->data.name, name);
p->data.brithday = brithday;
p->data.die = die;
//显示文件的东西
cout << "辈分:" << p->data.beifen << " ";
cout << "名字:" << p->data.name << " ";
cout << "出生:" << p->data.brithday << " ";
cout << "是否存活 0否1是:" << p->data.die << endl;
}
void find_Function(TreeNode* p, char name[]) //查找功能
{
p = findLocation(p, name);
if (p == NULL) {
cout << "当前为空节点" << endl;
}
else {
cout << "辈分:" << p->data.beifen << " ";
cout << "姓名:" << p->data.name << " ";
cout << "出生:" << p->data.brithday << " " << endl;
cout << p->data.name << "的子女:" << endl;
if (p->lc == NULL)
{
cout << "无左孩子!";
}
else {
cout << "辈分:" << p->lc->data.beifen << " ";
cout << "名字:" << p->lc->data.name << endl;
}
if (p->rc == NULL)
{
cout << "无右孩子!";
}
else {
cout << "辈分:" << p->rc->data.beifen << " ";
cout << "名字:" << p->rc->data.name << endl;
}
}
}
void add_Function(TreeNode* t)//添加功能
{
TreeNode* p, * q;
char name[20];
cout << "这位是谁的孩子:" << endl;
cin >> name;
q = findLocation(t, name);//查找当前名字返回的变量,为父亲节点
if (q == NULL)
{
cout << "双亲不存在" << endl;
}
else {
p = creatNode();//如果有这个父亲,就创建一个新的节点
if (p) {
p->data.beifen = q->data.beifen + 1; // 这是其父亲的辈分加 1
p->lc = p->rc = NULL;
if (q->lc == NULL) {
q->lc = p;
cout << "插入左子树成功!" << endl;
}
else {
q = q->lc;
//使用兄弟链表法
while (q->rc != NULL) {
q = q->rc;
}
q->rc = p;
cout << "插入右子树成功!" << endl;
}
}
}
}
void bianli(TreeNode* p, char father[])//写入祖宗
{
ofstream w("D://in1.txt", ios::app);//追加
if (!w) {
cerr << "file could not be open." << endl;
exit(0);
}
TreeNode* q;
if (p)//左子树的不为空
{
w << father << "\t" << p->data.beifen << "\t" << p->data.name << "\t"
<< p->data.brithday << "\t" << p->data.die << endl;
bianli(p->lc, p->data.name); //遍历左子树
q = p->rc;
while (q) //遍历右子树
{
w << father << "\t" << q->data.beifen << "\t" << q->data.name << "\t"
<< q->data.brithday << "\t" << p->data.die << endl;
bianli(q->lc, q->data.name);
q = q->rc;
}
}
w.close();
}
void save_File(TreeNode* p) //保存文件功能
{
ofstream ofile;
ofile.open("D://in1.txt", ios::out);//清空文件
if (!ofile) {
cerr << "file could not be open." << endl;
exit(0);
}
if (p) {
ofile << "\t" << p->data.beifen << "\t" << p->data.name << "\t"
<< p->data.brithday << "\t" << p->data.die << "\t" << endl;
if (p->lc) {
bianli(p->lc, p->data.name);//兄弟链表,左子树开始遍历
}
}
ofile.close();
}
void tree(char father[], char son[], int dai, int brithday, int die)//生成树
{
TreeNode* t;
TreeNode* p;
p = findLocation(root, father);//爸爸
if (p == NULL) { return; }
t = findLocation(root, son);//儿子,找空的位置
if (t != NULL) { return; }
if (p->lc == NULL)//添加孩子
{
p->lc = new Node;
p->lc->rc = p->lc->lc = NULL;
cunru(p->lc, son, dai, brithday, die);
cout << "插入左子树成功!" << endl;
}
else//添加前一个孩子的兄弟
{
p = p->lc;
while (p->rc != NULL)
p = p->rc;
p->rc = new Node;
p->rc->rc = p->rc->lc = NULL;
cunru(p->rc, son, dai, brithday, die);
cout << "插入右子树成功!" << endl;
}
}
void read_File() {
int dai, brithday, die;
char son[10], father[10];
root = new Node;//创建一个根节点
root->lc = root->rc = NULL;
ifstream read("D://in1.txt");//文件不存在会返回错误
if (!read) {
cerr << "file could not be open." << endl;
exit(0);
}
read >> dai >> father >> brithday >> die;//读入祖宗
cunru(root, father, dai, brithday, die);//存入结构体
while (!read.eof())//如果不为空
{
read >> father >> dai >> son >> brithday >> die;//读取儿子
tree(father, son, dai, brithday, die);//存入结构体
}
read.close();
}
void delete_Function(TreeNode*& p, char name[])//删除功能
{
//地址指针
if (p != NULL) {
if (strcmp(p->data.name, name) == 0)
{
p = NULL;//当前节点值为空
delete p;//删除当前节点
cout << "删除成功!!!" << endl;
return;
}
else
{
cout << "查无此人" << endl;
}
if (p->lc != NULL) { delete_Function(p->lc, name); }//找不到就遍历左边;
if (p->rc != NULL) { delete_Function(p->rc, name); }//找不到就遍历右边;
}
}
void look(TreeNode* p) // 前序遍历
{
if (p == NULL)return;
else {
putchar('(');
cout << p->data.name;
look(p->lc);
look(p->rc);
putchar(')');
}
}
void printAll(TreeNode* p) {
if (p != NULL) {
cout << "辈分:" << p->data.beifen << " ";
cout << "姓名:" << p->data.name << " ";
cout << "出生:" << p->data.brithday << " ";
cout << "是否存活 0否1是:" << p->data.die << " " << endl;
if (p->lc != NULL) { printAll(p->lc); }//遍历孩子
if (p->rc != NULL) { printAll(p->rc); }//遍历兄弟
}
}
void menu() {
cout << endl;
cout << "--------------------------------------------------------" << endl;
cout << ">>> 1 --- 添加祖宗 <<<" << endl;
cout << ">>> 2 --- 添加儿子 <<<" << endl;
cout << ">>> 3 --- 删除名字 <<<" << endl;
cout << ">>> 4 --- 查询一代人信息 <<<" << endl;
cout << ">>> 5 --- 查找名字 <<<" << endl;
cout << ">>> 6 --- 括号法前序遍历 <<<" << endl;
cout << ">>> 7 --- 遍历全部信息 <<<" << endl;
cout << ">>> 9 --- 手动保存 <<<" << endl;
cout << ">>> 10 --- 手动读取 <<<" << endl;
cout << ">>> 11 --- 清屏 <<<" << endl;
cout << "--------------------------------------------------------" << endl;
}
int main()
{
int m;
char name[20];
while (1) {
menu();
cout << ">>请输入选项>>:";
cin >> m;
switch (m) {
case 1:
if (root != NULL) { cout << "已经存在祖宗!" << endl; }
else { root = creatFirst(); } break;
case 2:
if (root == NULL) { cout << "请创建祖宗先" << endl; break; }
add_Function(root); break;
case 3:
if (root == NULL) { cout << "请创建祖宗先" << endl; break; }
cout << "输入删除的姓名" << endl; cin >> name; delete_Function(root, name); break;
case 4:
if (root == NULL) { cout << "请创建祖宗先" << endl; break; }
char ch1;
cout << "请输入这一代的字" << endl;
cin >> ch1;
searchByChar(root, ch1);
case 5:
if (root == NULL) { cout << "请创建祖宗先" << endl; break; }
cout << "输入查找的姓名" << endl;
cin >> name;
find_Function(root, name); break;
case 6:
if (root == NULL) { cout << "请创建祖宗先" << endl; break; }
look(root); break;
case 7:
if (root == NULL) { cout << "请创建祖宗先" << endl; break; }
printAll(root); break;
case 9:
if (root == NULL) { cout << "请创建祖宗"; break; }
save_File(root); cout << "保存成功!!!" << endl; break;
case 10:
read_File(); break;
case 11:
system("cls"); break;
default:
cout << "输入错误!!!" << endl; break;
}
}
system("pause");
return 0;
}
(1)读取
(2)插入:给某个人添加一个孩子
(3)删除:删除某个人,如果某人有后代,不允许删除
(4)堂兄弟:根据所在世代的字,可以输出该世代所有人的信息
(5)父子:可以根据姓名查询,并输出该人的父亲和孩子信息
(6)显示:以凹入表的形式显示家谱
(7)退出时,家谱信息保存到文件中