C语言家谱管理系统(孩子兄弟树)

【问题描述】

家谱记载了一个家族的世系繁衍及重要人物事迹。使用树型结构对家谱进行管理,实现查看祖先和子孙个人信息,插入家族成员,删除家族成员的功能。

基本要求

(1)采用树型结构完成对家谱成员信息的建立。可利用孩子兄弟表示方法表示树型结构。

(2)完成家谱成员信息查找,插入,修改,删除功能。

(3)判断两个人的家族关系。

(4)进行子孙、祖先、堂兄弟关系的查询。

扩展要求

(1)实现树的层次遍历,显示家族每一代的成员。

(2)打印家谱的树型结构操作。

(3)判断两个成员是否属于直系或旁系三代关系

(4)自行设计家谱的其它操作。

程序执行部分截图:

common.h

#pragma once

//常量定义
#define TRUE   1
#define FALSE  0
#define OK     1
#define ERROR  0
#define UOVERFLOW -1
#define EINFINITY -2

//类型定义
typedef int Status;
typedef char TElemType;


typedef struct {

    char name[20];//姓名

    char sex[5];//性别 1为男性 0为女性

    long int birthYear;//出生年份

    long int endYear;//寿终年份   Infinity表示在世

}Member;

//树的孩子兄弟链表的类型定义:
typedef struct CSTNode {
    Member data; //数据域
    struct CSTNode* firstChild, * nextSibling;
    //左孩子指针,右兄弟指针
}CSTNode, * CSTree, * CSForest; //孩子兄弟链表

typedef struct LSNode {
    CSTree data;    // 数据域
    struct LSNode* next;    // 指针域
} LSNode, * LStack;    // 结点和链栈类型

typedef struct {
    CSTree* elem;
    int front; //队头位标
    int rear; //队尾位标,队尾元素下一个位置
    int maxSize;
}SqQueue;

//获取当前年份
int GetYear() {
    time_t nowtime;
    time(&nowtime); //获取1970年1月1日0点0分0秒到现在经过的秒数
    tm p;
    localtime_s(&p, &nowtime);
    int year = p.tm_year + 1900;
    return year;
}

//打印成员信息
void PrintMemberMessage(Member member) {
    printf(" %s",member.name);
    printf("\t\t%s", member.sex);
    printf("\t  %ld", member.birthYear);
    if (member.endYear == EINFINITY) {
        int age = GetYear() - member.birthYear;
        printf("\t\t    %d", age);
    }
    else printf("\t\t   %ld", member.endYear);
    return;
}

//用空格分割字符串
int partition(char* src, char* par, int pos) {
    int i, j;
    i = pos;
    // 取到第一个非空格字符
    while (src[i] == ' ') {
        ++i;
    }
    if (src[i] != '\0') {
        j = 0;
        while ((src[i] != ' ') && (src[i] != '\0')) {
            par[j++] = src[i++];
        }
        par[j] = '\0';
        return i;
    }
    return -1;
}

LStack.h

​
#pragma once

Status InitStack_LS(LStack& S)
{ // 初始化空链栈S
    //Add your code here
    S = NULL;
    return OK;
}

//进栈
Status Push_LS(LStack& S, CSTree e)
{
    LSNode* t;
    t = (LSNode*)malloc(sizeof(LSNode)); // 为元素e生成一个新结点
    if (NULL == t)
    {
        return OVERFLOW; // 生成失败,返回
    }

    t->data = e;
    t->next = S;
    S = t;
    return OK;
}

//出栈
Status Pop_LS(LStack& S, CSTree& e)
{
    LSNode* t;
    if (NULL == S)
    {
        return ERROR; // 判断是否为空栈
    }
    t = S;
    e = t->data;
    S = t->next;
    return OK;
}

//判断栈是否为空
Status StackEmpty_LS(LStack S)
{
    if (NULL == S)
    {
        return TRUE;
    }
    return FALSE;
}

​

SqQueue.h

#pragma once

//初始化
Status InitQueue_Sq(SqQueue& Q, int size) {
	Q.elem = (CSTree*)(malloc(size * sizeof(CSTree)));
	if (NULL == Q.elem) return OVERFLOW;
	Q.maxSize = size;
	Q.front = Q.rear = 0;
	return OK;
}

//出队列
Status DeQueue_Sq(SqQueue& Q, CSTree& e) {
	if (Q.front == Q.rear) return ERROR;
	e = Q.elem[Q.front];
	Q.front = (Q.front + 1) % Q.maxSize;
	return OK;
}
//入队列
Status EnQueue_Sq(SqQueue& Q, CSTree& e) {
	if ((Q.rear + 1) % Q.maxSize == Q.front) return ERROR;
	Q.elem[Q.rear] = e;
	Q.rear = (Q.rear + 1) % Q.maxSize;
	return OK;
}
//判空
Status QueueEmpty_Sq(SqQueue Q) {
	return Q.front == Q.rear ? TRUE : FALSE;
}

CSTreeOperate.h

#pragma once

//以下为定义的树的各项操作

//初始化空树T
Status InitTree(CSTree& T) {
    T = NULL;
    return OK;
}

//创建根结点e和n棵子树的树
CSTree MakeTree(Member e, int n, ...) {
    int i; CSTree t, p, pi;
    va_list argptr;
    t = (CSTNode*)malloc(sizeof(CSTNode));
    if (NULL == t) return NULL;
    t->data = e;
    t->firstChild = t->nextSibling = NULL;
    if (n <= 0) return t;
    va_start(argptr, n);
    p = va_arg(argptr, CSTree);
    t->firstChild = p;
    pi = p;
    for (i = 1; i < n; i++) {
        p = va_arg(argptr, CSTree);
        pi->nextSibling = p;
        pi = p;
    }
    va_end(argptr);
    return t;
}

//创建一棵树(实质为创建二叉树)
CSTree CreateTree(Member* members, int& i)
{   // 按str先序构造二叉树的二叉链表,i为str的当前位标,初值为0
    CSTree T;
    InitTree(T);
    Member member = members[i++];
    if (!strcmp(member.name,"#"))
    {
        InitTree(T); // 空树
    }
    else
    {
        T = MakeTree(member, 0);      // 构造结点ch
        T->firstChild = CreateTree(members, i); // 构造孩子
        T->nextSibling = CreateTree(members, i); // 构造兄弟
    }
    return T;
}

//求结点在树中的层次
int NodeLevel(CSTree T, char* target) {
	if (T == NULL) {
		return -1; // 树为空,返回-1表示未找到
	}
	if (T->data.name == target) {
		return 0; // 根节点就是目标节点,层次为0
	}
	int level = -1; // 初始化层次为-1,表示未找到
	CSTree p = T->firstChild;
	while (p != NULL) {
		int childLevel = NodeLevel(p, target); // 递归求子节点的层次
		if (childLevel != -1) {
			level = childLevel + 1; // 子节点层次加1即为当前节点的层次
			break;
		}
		p = p->nextSibling;
	}
	return level;
}

//层序遍历一棵树(队列)
void LevelOrder(CSTree T)
{
	SqQueue Q;
	InitQueue_Sq(Q, 20);
	CSTree p = T;
	EnQueue_Sq(Q, p);
	while (!QueueEmpty_Sq(Q))
	{
		DeQueue_Sq(Q, p);
		PrintMemberMessage(p->data);
		printf("\t\t【%d世】", NodeLevel(T, p->data.name) + 1);
		printf("\n");
		p = p->firstChild;
		while (p)
		{
			EnQueue_Sq(Q, p);
			p = p->nextSibling;
		}
	}
}

//森林的查找
CSTNode* Search(CSForest F, char name[20]) {
	//查找森林F中的结点e的name并返回其指针
	CSTNode* result = NULL;
	if (NULL == F) return NULL;
	if (!strcmp(F->data.name, name)) return F;
	if ((result = Search(F->firstChild, name)) != NULL) return result;
	return Search(F->nextSibling, name);
}

//插入一个结点
Status InsertNode(CSTree T, CSTree FaNode, Member ChNode) {
	if (NULL == T) return ERROR;
	if (NULL == T) return ERROR;
	else {
		CSTNode* t = (CSTNode*)malloc(sizeof(CSTNode));
		if (NULL == t) return UOVERFLOW;
		t->data = ChNode;
		if (!FaNode->firstChild) {
			FaNode->firstChild = t;
		}
		else {
			CSTree q = FaNode->firstChild;
			while (q->nextSibling)
			{
				q = q->nextSibling;
			}
			q->nextSibling = t;
		}
		t->firstChild = t->nextSibling = NULL;
	}
	return OK;
}

//删除结点(最近一级父节点)

//销毁树
void DestroyTree(CSTree& T) {
	if (T) {
		if (T->firstChild)
			DestroyTree(T->firstChild);
		else if (T->nextSibling)
			DestroyTree(T->nextSibling);
		free(T);
	}
}

//重新连接断口
void Reconnect(CSTNode* rootNode, CSTNode* desNode) {
	if (rootNode->firstChild == desNode) {
		rootNode->firstChild = desNode->nextSibling;
	}
	if (rootNode->nextSibling == desNode) {
		rootNode->nextSibling = desNode->nextSibling;
	}
	desNode->nextSibling = NULL;
	DestroyTree(desNode);
}

Status DeleteNode(CSTree T, char rootNode[20], char desNode[20]) {
	if (NULL == T) return OK;
	CSTree p = Search(T, rootNode);
	CSTree q = Search(T, desNode);
	if (NULL == p || NULL == q) return ERROR;
	if (!p->firstChild) return ERROR;
	if (p->firstChild == q) {
		if (!p || !q) return ERROR;
		Reconnect(p, q);
	}
	else {
		p = p->firstChild;
		while (p && p->nextSibling != q)
		{
			p = p->nextSibling;
		}
		if (!p || !q) return ERROR;
		Reconnect(p, q);
	}
	return OK;
}

//判断成员关系

//是否是直系(后代结点是否在前代结点的子树上)
Status IsDirectRelationship(CSTree T, CSTree p, CSTree q) {
	if (NULL == T) return UOVERFLOW;
	CSTree t = p;
	while (t->nextSibling)
	{
		if (t->nextSibling == q) return 1;
		t = t->nextSibling;
	}
	p = p->firstChild;
	LStack S; InitStack_LS(S);
	while (p || !StackEmpty_LS(S)) {
		while (p) {
			if (p == q) return 1;
			Push_LS(S, p);
			p = p->firstChild;
		}
		Pop_LS(S, p);
		if (p) p = p->nextSibling;
	}
	return 0;
}

//是否为旁系(后代结点是否在前代结点兄弟树上)
Status IsCollateralRelationship(CSTree T, CSTree p, CSTree q) {
	if (!IsDirectRelationship(T, p, q)) return 1;
	return 0;
}

GenealogyOperate.h

#pragma once

//函数参数
typedef void(*handler)(CSTree);
typedef void(*callback)(Member&,CSTree T);
typedef void(*_callback)(Member&, Member&, CSTree T);

//家谱管理系统操作
Member* GetMembers();         /*获取成员数组*/
Member EmptyNode();           /*空结点(是否创建空树)*/
Member* CreateMemeberTree();       /*创建家谱树结构数组*/
void CreateFamilyTree(CSTree& T);        /*创建家谱*/
Status IsContinue();        /*是否继续*/
void Prompt(CSTree T,const char ch1[20], const char ch2[20], handler h);     /*提示框*/
void ShowFamilyMembers(CSTree T);       /*显示家谱成员(层序遍历)*/
void SearchFamilyMember(CSTree T);         /*查找家谱成员*/
void CascadingMenu(CSTree T);          /*修改家谱成员的级联菜单*/
void ChangeMemberName(CSTree T,CSTree member);        /*修改成员姓名*/
void ChangeMemberSex(CSTree T, CSTree member);       /*修改成员性别*/
void ChangeMemberBirthYear(CSTree T, CSTree member);      /*修改成员出生日期*/
void ChangeMemberEndYear(CSTree T, CSTree member);        /*修改成员寿终日期*/
void AddMember(CSTree T);         /*添加家谱成员*/
void StepPrompt(CSTree T,Member& m, callback c1, callback c2);       /*步骤提示框*/
void AddName(Member& chNode,CSTree T);     /*输入添加成员姓名*/
void AddSex(Member& chNode, CSTree T);      /*输入添加成员性别*/
void AddBirthYear(Member& chNode, CSTree T);           /*输入添加成员出生年*/
void AddEndYear(Member& chNode, CSTree T);          /*输入添加成员寿终年*/
void DeleteMember(CSTree T);              /*删除家谱成员*/
void StepTip(Member& ch, Member& fa, CSTree T,callback c1,_callback c2);       /*步骤提示*/
void CheckFaNode(Member& fa,Member& ch,CSTree T);            /*输入检测父节点*/
void CheckChNode(Member& m,CSTree T);            /*输入检测子节点*/
void CoutMembers(CSTree T);             /*统计家谱成员*/
int CoutMembersNum(CSTree T,int& num);           /*统计家谱成员数量*/
float CoutLife(CSTree T, float& total);         /*统计家谱成员总寿命*/
int CoutDeadMember(CSTree T, int& num);         /*统计寿终成员数量*/
float CountMaleNum(CSTree T,float& maleNum);            /*统计男性数量*/
float CountFemaleNum(CSTree T,float& femaleNum);           /*统计女性数量*/
void Members_Relationship(CSTree T);              /*家谱成员关系*/
void CheckPreNode(Member& pre, Member& des, CSTree T);           /*输入检测前代节点*/
void CheckDesNode(Member& des, CSTree T);            /*输入检测后代结点*/
int GetRelationshipBySex(CSTree p, CSTree q);         /*通过性别获取关系*/
void InquireRelationship(CSTree T);
void InquireSons(CSTree T,CSTree t);
void InquireAncestor(CSTree T, CSTree t);
void InquireCousin(CSTree T, CSTree t);
void PrintAsTree(CSTree b);               /*打印家谱树*/
void Menu(CSTree T);         /*菜单*/

//以下为创建家谱树过程

//获取成员数组
Member* GetMembers() {
	//创建家谱成员数组
	Member* members = (Member*)malloc(sizeof(Member) * 50);
	if (members == NULL) return NULL;
	//打开文件
	FILE* fp = NULL;
	fopen_s(&fp, "data.txt", "r");
	if (!fp) {
		printf("失败");
		return NULL;
	}
	//开始添加成员到数组
	int j = 0;
	while (!feof(fp))
	{
		//行式读取文件
		char src[1024] = { '\0' };
		fgets(src, 1024, fp);
		int i = 0;
		char par[20];
		int pos = 0;
		//用空格分割字符串
		while ((pos = partition(src, par, pos)) != -1) {
			if (i == 0) strcpy_s(members[j].name, par);
			else if (i == 1) strcpy_s(members[j].sex, par);
			else if (i == 2) members[j].birthYear = atoi(par);
			else if (i == 3) members[j].endYear = atoi(par);
			i++;
		}
		j++;
	}
	//关闭文件
	fclose(fp);

	return members;
}

//空结点(是否创建空树)
Member EmptyNode() {
	return { "#","#",0,0 };
}

//创建家谱树结构数组
Member* CreateMemeberTree() {
	//获取家谱成员
	Member* members = GetMembers();
	
	//创建家谱树结构数组
	Member* memberTree = (Member*)malloc(sizeof(Member) * 80);
	if (NULL == memberTree) return NULL;

	memberTree[0] = members[0]; memberTree[1] = members[1]; memberTree[2] = members[2]; memberTree[3] = members[3]; memberTree[4] = EmptyNode();
	memberTree[5] = members[4]; memberTree[6] = members[5]; memberTree[7] = members[6]; memberTree[8] = EmptyNode(); memberTree[9] = EmptyNode();
	memberTree[10] = EmptyNode(); memberTree[11] = EmptyNode(); memberTree[12] = members[7]; memberTree[13] = members[8]; memberTree[14] = members[9];
	memberTree[15] = EmptyNode(); memberTree[16] = EmptyNode(); memberTree[17] = EmptyNode(); memberTree[18] = members[10]; memberTree[19] = EmptyNode();
	memberTree[20] = members[11]; memberTree[21] = members[12]; memberTree[22] = members[13]; memberTree[23] = EmptyNode(); memberTree[24] = EmptyNode();
	memberTree[25] = EmptyNode(); memberTree[26] = EmptyNode(); memberTree[27] = members[14]; memberTree[28] = EmptyNode(); memberTree[29] = members[15];
	memberTree[30] = members[16]; memberTree[31] = EmptyNode(); memberTree[32] = members[17]; memberTree[33] = members[18]; memberTree[34] = members[19];
	memberTree[35] = members[20]; memberTree[36] = EmptyNode(); memberTree[37] = EmptyNode(); memberTree[38] = members[21]; memberTree[39] = EmptyNode();
	memberTree[40] =EmptyNode(); memberTree[41] = members[22]; memberTree[42] =members[23]; memberTree[43] = EmptyNode(); memberTree[44] = EmptyNode();
	memberTree[45] = EmptyNode(); memberTree[46] =members[24]; memberTree[47] = members[25]; memberTree[48] = EmptyNode(); memberTree[49] = members[26];
	memberTree[50] = members[27]; memberTree[51] = EmptyNode(); memberTree[52] = EmptyNode(); memberTree[53] = members[28]; memberTree[54] = members[29];
	memberTree[55] = EmptyNode(); memberTree[56] = EmptyNode(); memberTree[57] = members[30]; memberTree[58] = EmptyNode(); memberTree[59] = members[31];
	memberTree[60] = EmptyNode(); memberTree[61] = members[32]; memberTree[62] = EmptyNode(); memberTree[63] = EmptyNode(); memberTree[64]=members[33];
	memberTree[65] = members[34]; memberTree[66] = members[35]; memberTree[67] = EmptyNode(); memberTree[68] = EmptyNode(); memberTree[69] = members[36];
	memberTree[70] = members[37]; memberTree[71] = EmptyNode(); memberTree[72] = EmptyNode(); memberTree[73] = EmptyNode(); memberTree[74] = EmptyNode();
	memberTree[75] = EmptyNode(); memberTree[76] = EmptyNode();

	return memberTree;

}

//创建家谱
void CreateFamilyTree(CSTree& T) {
	//初始化家谱树
	InitTree(T);

	//创建家谱树
	int i = 0;
	Member* membersTree = CreateMemeberTree();
	T=CreateTree(membersTree, i);
}

//是否继续
Status IsContinue() {
	char ch = '\0';
	rewind(stdin);
	scanf_s("%c", &ch, 1);
	if (ch == '1') return 1; //继续
	else if (ch == '0') return 0; //退出
	else return -1; //ERROR;
}

//提示框
void Prompt(CSTree T, const char ch1[20], const char ch2[20], handler h)
{
	printf("提示(1:%s,0:%s):", ch1, ch2);
	int choice = 0;
	char ch = '\0';
	rewind(stdin);
	scanf_s("%c", &ch, 1);
	if (ch == '1') choice = 1; //继续
	else if (ch == '0') choice = 0; //退出
	else choice = -1; //ERROR;
	if (choice == 1) h(T);
	else if (choice == 0) return;
	else if (choice == -1) {
		printf("输入有误,");
		Prompt(T, ch1, ch2, h);
	}
	return;
}

//显示家谱成员(层序遍历)
void ShowFamilyMembers(CSTree T) {
	system("cls");
	printf("╔-------------------------------------------------------------╗\n");
	printf("\t\t\t$ 显示家谱成员 $\n\n");
	printf(" 姓名\t\t性别\t出生日期\t寿终日期(年龄)\n");
	LevelOrder(T);
	printf("\n");
	printf("╚-------------------------------------------------------------╝\n");
	Prompt(T, "返回", "退出", Menu);
}

//查找家谱成员
void SearchFamilyMember(CSTree T) {
	printf("请输入您要查找的成员的姓名:");
	char name[20] = { 0 };
	rewind(stdin);
	scanf_s("%s", &name, 20);
	CSTree member = Search(T, name);
	if (member!=NULL) {
		if (!strcmp(name, member->data.name)) {
			system("cls");
			printf("╔-------------------------------------------------------------╗\n");
			printf("\t\t\t$ 查找家谱成员 $\n\n");
			printf(" 姓名\t\t性别\t出生日期\t寿终日期(年龄)\n");
			PrintMemberMessage(member->data);
			printf("\t\t【%d世】", NodeLevel(T, member->data.name) + 1);
			printf("\n\n");
			printf("╚-------------------------------------------------------------╝\n");
			Prompt(T, "返回", "退出", Menu);
		}
		else {
			printf("家谱中不存在此人,请检查拼写错误\n");
			Prompt(T, "重新输入", "退出", SearchFamilyMember);
		}
	}
	else {
		printf("家谱中不存在此人,请检查拼写错误\n");
		Prompt(T, "重新输入", "退出", SearchFamilyMember);
	}
	return;
}

//修改家谱成员的级联菜单
void CascadingMenu(CSTree T) {
	printf("请输入您要修改的成员的姓名:");
	char name[20] = { 0 };
	rewind(stdin);
	scanf_s("%s", &name, 20);
	CSTree member = Search(T, name);
	if (!member) {
		printf("家谱中不存在此人,请检查拼写错误\n");
		Prompt(T, "重新输入", "退出", CascadingMenu);
		return;
	}
	system("cls");
	printf("查找成功!!!\n");
	up:
	printf("\t\t\t\t\t\t\t$ 修改家谱成员 $\n\n");
	printf("\t\t\t\t\t\t\t1 # 修改成员姓名\n");
	printf("\t\t\t\t\t\t\t2 # 修改成员性别\n");
	printf("\t\t\t\t\t\t\t3 # 修改出生日期\n");
	printf("\t\t\t\t\t\t\t4 # 修改寿终日期\n");
	printf("\t\t\t\t\t\t\t5 # 返回主菜单\n");
	printf("\t\t\t\t\t\t\t0 # 退出\n\n");
	printf("\t\t\t\t\t\t╚-----------------------------╝\n");

	//菜单功能实现
	printf("请输入您要选择的功能:");
	char choice = '0';
	rewind(stdin);
	scanf_s("%c", &choice, 1);
	switch (choice)
	{
	case '1': ChangeMemberName(T,member);
		break;
	case '2':ChangeMemberSex(T, member);
		break;
	case '3':ChangeMemberBirthYear(T, member);
		break;
	case '4':ChangeMemberEndYear(T, member);
		break;
	case '5':Menu(T);
		break;
	case '0':return;
	default: {printf("请输入正确的数字!!!\n"); goto up; };
		break;
	}
	return;
}

//修改成员姓名
void ChangeMemberName(CSTree T,CSTree member) {
	printf("请输入修改后的姓名:");
	char name[20] = { 0 };
	rewind(stdin);
	scanf_s("%s", &name,20);
	strcpy_s(member->data.name,name);
	printf("修改成功,");
	Prompt(T, "返回主菜单", "退出",Menu);
	return;
}

//修改成员性别
void ChangeMemberSex(CSTree T, CSTree member) {
	printf("请输入修改后的性别:");
	char sex[10] = { 0 };
	rewind(stdin);
	scanf_s("%s", &sex, 10);
	if (strcmp(sex, "男")&&strcmp(sex, "女")) {
		printf("请输入正确的性别!!!\n");
		ChangeMemberSex(T, member);
	}
	strcpy_s(member->data.sex, sex);
	printf("修改成功,");
	Prompt(T, "返回主菜单", "退出", Menu);
	return;
}

//修改成员出生日期
void ChangeMemberBirthYear(CSTree T, CSTree member) {
	printf("请输入修改后的出生年:");
	char birthYear[10] = { 0 };
	rewind(stdin);
	scanf_s("%s", &birthYear, 10);
	member->data.birthYear = atoi(birthYear);
	printf("修改成功,");
	Prompt(T, "返回主菜单", "退出", Menu);
	return;
}

//修改成员寿终日期
void ChangeMemberEndYear(CSTree T, CSTree member) {
	printf("请输入修改后的寿终年(如果成员在世,请输入-2):");
	char endYear[10] = { 0 };
	rewind(stdin);
	scanf_s("%s", &endYear, 10);
	member->data.endYear = atoi(endYear);
	printf("修改成功,");
	Prompt(T, "返回主菜单", "退出", Menu);
	return;
}

//添加家谱成员
//步骤提示框
void StepPrompt(CSTree T,Member& m,callback c1,callback c2) {
	printf("提示(1:下一步,0:上一步):");
	int choice = 0;
	char ch = '\0';
	rewind(stdin);
	scanf_s("%c", &ch, 1);
	if (ch == '1') choice = 1; //下一步
	else if (ch == '0') choice = 0; //上一步
	else choice = -1; //ERROR;
	if (choice == 1) c1(m,T);
	else if (choice == 0) c2(m,T);
	else if (choice == -1) {
		printf("输入有误,");
		StepPrompt(T,m, c1, c2);
	}
	return;
}

void AddMember(CSTree T) {
	printf("请输入被添加成员的父(母)亲的姓名:");
	char faName[20] = { 0 };
	rewind(stdin);
	scanf_s("%s", &faName,20);
	CSTree faNode = Search(T, faName);
	if (NULL == faNode) {
		printf("家谱中不存在此人!!!\n");
		AddMember(T);
		return;
	}
	Member chNode = EmptyNode();
	AddName(chNode,T);
	InsertNode(T, faNode, chNode);
	printf("添加成功\n");
	Prompt(T, "返回", "退出", Menu);
	return;
}

//输入添加成员姓名
void AddName(Member& chNode, CSTree T) {
	printf("请输入添加成员的姓名:");
	char chName[20] = { 0 };
	rewind(stdin);
	scanf_s("%s", &chName, 20);
	strcpy_s(chNode.name, chName);
	StepPrompt(T,chNode, AddSex, AddName);
	return;
}

//输入添加成员性别
void AddSex(Member& chNode, CSTree T) {
	printf("请输入添加成员的性别:");
	char chSex[10] = { 0 };
	rewind(stdin);
	scanf_s("%s", &chSex, 10);
	strcpy_s(chNode.sex, chSex);
	StepPrompt(T,chNode, AddBirthYear, AddSex);
	return;
}

//输入添加成员出生年
void AddBirthYear(Member& chNode, CSTree T) {
	printf("请输入添加成员的出生年:");
	char chBirthYear[10] = { 0 };
	rewind(stdin);
	scanf_s("%s", &chBirthYear, 10);
	if (!atoi(chBirthYear)) {
		printf("请输入正确的年份\n");
		AddBirthYear(chNode,T);
	}
	chNode.birthYear = atoi(chBirthYear);
	StepPrompt(T,chNode,AddEndYear,AddBirthYear);
	return;
}

//输入添加成员寿终年
void AddEndYear(Member& chNode,CSTree T) {
	printf("请输入添加成员的寿终年(若成员在世请输入-2):");
	char chEndYear[10] = { 0 };
	rewind(stdin);
	scanf_s("%s", &chEndYear, 10);
	if (!atoi(chEndYear)) {
		printf("请输入正确的年份\n");
		AddEndYear(chNode,T);
	}
	chNode.endYear = atoi(chEndYear);
	return;
}

//删除家谱成员

//步骤提示
void StepTip(Member& ch,Member& fa,CSTree T,callback c1,_callback c2) {
	printf("提示(1:下一步,0:上一步):");
	int choice = IsContinue();
	if (choice == 1) c1(ch, T);
	else if (choice == 0) c2(ch,fa,T);
	else StepTip(ch, fa, T,c1,c2);
	return;
}

void DeleteMember(CSTree T) {
	Member fa = EmptyNode(); Member ch = EmptyNode();
	CheckFaNode(fa,ch,T);
	if (DeleteNode(T, fa.name, ch.name)) {
		printf("删除成功!!!\n");
	}
	else {
		printf("以上输入的两名成员不存在父(母)子(女)关系\n");
	}
	Prompt(T, "返回", "退出", Menu);
	return;
}

//输入检测父节点
void CheckFaNode(Member& fa,Member& ch,CSTree T) {
	printf("请输入删除成员的父(母)亲的姓名:");
	char faName[20] = { 0 };
	rewind(stdin);
	scanf_s("%s", &faName, 20);
	CSTree faNode = Search(T,faName);
	if (!faNode) {
		printf("家谱中不存在此人!!!\n");
		CheckFaNode(fa,ch,T);
		return;
	}
	else {
		printf("查找成功!!!\n");
		strcpy_s(fa.name, faName);
	}
	StepTip(ch, fa, T,CheckChNode, CheckFaNode);
	return;
}

//输入检测子节点
void CheckChNode(Member& m, CSTree T) {
	printf("请输入删除成员的姓名:");
	char chName[20] = { 0 };
	rewind(stdin);
	scanf_s("%s", &chName, 20);
	CSTree chNode = Search(T, chName);
	if (!chNode) {
		printf("家谱中不存在此人!!!");
		CheckChNode(m,T);
		return;
	}
	printf("查找成功!!!\n");
	strcpy_s(m.name, chName);
	return ;
}

//统计家谱成员
void CoutMembers(CSTree T) {
	int num = 0;CoutMembersNum(T, num);  //家谱成员总数
	float totalLife = 0;CoutLife(T, totalLife); //寿终成员总寿命
	int deadNum = 0; CoutDeadMember(T, deadNum);
	float maleNum = 0; CountMaleNum(T, maleNum); //男性成员数
	float femaleNum = 0; CountFemaleNum(T, femaleNum);//女性成员总数
	system("cls");
	printf("\t\t\t\t\t\t╔-----------------------------╗\n");
	printf("\t\t\t\t\t\t\t$ 统计家谱成员 $\n");
	printf("\t\t\t\t\t\t\t成员数量:%d\n", num);
	printf("\t\t\t\t\t\t\t平均寿命:%.2f岁\n",totalLife / deadNum);
	printf("\t\t\t\t\t\t\t男性比例:%.2f%%\n", 100 * maleNum / num);
	printf("\t\t\t\t\t\t\t女性比例:%.2f%%\n", 100 * femaleNum / num);
	printf("\t\t\t\t\t\t╚-----------------------------╝\n");
	Prompt(T, "返回", "退出", Menu);
}

//统计成员数量
int CoutMembersNum(CSTree T,int& num) {
	if (NULL == T) return num;
	num++;
	CoutMembersNum(T->firstChild,num);
	CoutMembersNum(T->nextSibling,num);
	return num;
}

//统计成员总寿命
float CoutLife(CSTree T,float &total) {
	if (NULL == T) return total;
	if (T->data.endYear != EINFINITY) {
		total += T->data.endYear - T->data.birthYear;
	}
	CoutLife(T->firstChild,total);
	CoutLife(T->nextSibling,total);
	return total;
}

//统计寿终成员数量
int CoutDeadMember(CSTree T, int& num) {
	if (NULL == T) return num;
	if (T->data.endYear != EINFINITY) num++;
	CoutDeadMember(T->firstChild, num);
	CoutDeadMember(T->nextSibling, num);
	return num;
}

//统计男性数量
float CountMaleNum(CSTree T,float &maleNum) {
	if (NULL == T) return maleNum;
	if (!strcmp(T->data.sex,"男")) {
		maleNum++;
	}
	CountMaleNum(T->firstChild,maleNum);
	CountMaleNum(T->nextSibling,maleNum);
	return maleNum;
}

//统计女性数量
float CountFemaleNum(CSTree T,float &femaleNum) {
	if (NULL == T) return femaleNum;
	if (!strcmp(T->data.sex, "女")) {
		femaleNum++;
	}
	CountFemaleNum(T->firstChild,femaleNum);
	CountFemaleNum(T->nextSibling,femaleNum);
	return femaleNum;
}

//判断家谱中两人的关系
void Members_Relationship(CSTree T) {
	Member pre = EmptyNode(); Member des = EmptyNode();
	CheckPreNode(pre, des, T);
	CSTree p = Search(T, pre.name);
	CSTree q = Search(T, des.name);
	int Level1 = NodeLevel(T, p->data.name);
	int Level2 = NodeLevel(T, q->data.name);
	int result = abs(Level1 - Level2); int res = GetRelationshipBySex(p, q);
	system("cls");
	//成员1为前代,成员2为后代(直系)
	printf("╔-----------------------------╗\n");
	printf("\t$ 家谱成员关系 $\n");
	if (IsDirectRelationship(T, p, q)) {
		if (result == 0) {
			if (res == 0) printf("\t他们是兄弟关系\n");
			else if (res == 1) printf("\t他们是兄妹关系\n");
			else if (res == 2) printf("\t他们是姐弟关系\n");
			else printf("\t她们是姐妹关系\n");
		}
		else if (result == 1) {
			if (res == 0) printf("\t他们是父子关系\n");
			else if (res == 1) printf("\t他们是父女关系\n");
			else if (res == 2) printf("\t他们是母子关系\n");
			else printf("\t她们是母女关系\n");
		}
		else if (result == 2) {
			if (res == 0) printf("\t他们是爷孙关系\n");
			else if (res == 1) printf("\t他们是爷孙关系\n");
			else if (res == 2) printf("\t他们是婆孙关系\n");
			else printf("\t她们是婆孙关系\n");
		}
		else if (result >= 3) printf("\t他们是祖孙关系\n");
	}
	//成员1为后代,成员2为前代(直系)
	else if (IsDirectRelationship(T, q, p)) {
		if (result == 0) {
			if (res == 0) printf("\t他们是兄弟关系\n");
			else if (res == 1) printf("\t他们是姐弟关系\n");
			else if (res == 2) printf("\t他们是兄妹关系\n");
			else printf("\t她们是姐妹关系\n");
		}
		else if (result == 1) {
			if (res == 0) printf("\t他们是父子关系\n");
			else if (res == 1) printf("\t他们是母子关系\n");
			else if (res == 2) printf("\t他们是父女关系\n");
			else printf("\t她们是母女关系\n");
		}
		else if (result == 2) {
			if (res == 0) printf("\t他们是爷孙关系\n");
			else if (res == 1) printf("\t他们是婆孙关系\n");
			else if (res == 2) printf("\t他们是爷孙关系\n");
			else printf("\t她们是婆孙关系\n");
		}
		else if (result >= 3) printf("\t他们是祖孙关系\n");
	}
	//成员1为前代,成员2为后代(旁系)
	else if (IsCollateralRelationship(T, p, q)) {
		if (result == 0) {
			if (res == 0) printf("\t他们是堂兄弟关系\n");
			else if (res == 1) printf("\t他们堂兄妹关系\n");
			else if (res == 2) printf("\t他们堂姐弟关系\n");
			else printf("她们是堂姐妹关系\n");
		}
		else if (result == 1) {
			if (res == 0) printf("\t他们是叔侄关系\n");
			else if (res == 1) printf("\t他们是叔侄关系\n");
			else if (res == 2) printf("\t他们是婶侄关系\n");
			else printf("\t她们是婶侄关系\n");
		}
		else if (result == 2) printf("\t他们是三代内旁系\n"); 
		else if (result >= 3) printf("\t他们是三代外旁系\n");
	}
	//成员1为后代, 成员2为前代(旁系)
	else if (IsCollateralRelationship(T, q, p)) {
		if (result == 0) {
			if (res == 0) printf("\t他们是堂兄弟关系\n");
			else if (res == 1) printf("\t他们堂姐弟关系\n");
			else if (res == 2) printf("\t他们堂兄妹关系\n");
			else printf("\t她们是堂姐妹关系\n");
		}
		else if (result == 1) {
			if (res == 0) printf("\t他们是叔侄关系\n");
			else if (res == 1) printf("\t他们是婶侄关系\n");
			else if (res == 2) printf("\t他们是叔侄关系\n");
			else printf("\t她们是婶侄关系\n");
		}
		else if (result == 2) printf("\t他们是三代内旁系\n");
		else if (result >= 3) printf("\t他们是三代外旁系\n");
	}
	printf("╚-----------------------------╝\n");
	Prompt(T, "返回", "退出", Menu);
	return;
}

//输入查找成员1
void CheckPreNode(Member& pre, Member& des, CSTree T) {
	printf("请输入第一个成员的姓名:");
	char preName[20] = { 0 };
	rewind(stdin);
	scanf_s("%s", &preName, 20);
	CSTree preNode = Search(T, preName);
	if (!preNode) {
		printf("家谱中不存在此人!!!\n");
		CheckPreNode(pre, des, T);
		return;
	}
	else {
		printf("查找成功!!!\n");
		strcpy_s(pre.name, preName);
	}
	StepTip(des, pre, T, CheckDesNode, CheckPreNode);
	return;
}

//输入查找成员2
void CheckDesNode(Member& des, CSTree T) {
	printf("请输入第二个成员的姓名:");
	char desName[20] = { 0 };
	rewind(stdin);
	scanf_s("%s", &desName, 20);
	CSTree desNode = Search(T, desName);
	if (!desNode) {
		printf("家谱中不存在此人!!!");
		CheckDesNode(des, T);
		return;
	}
	printf("查找成功!!!\n");
	strcpy_s(des.name, desName);
	return;
}

//由性别输出具体关系
int GetRelationshipBySex(CSTree p,CSTree q) {
	if (strcmp(p->data.sex, "男") == 0 && strcmp(q->data.sex, "男") == 0) return 0; //两个成员均为男
	else if (strcmp(p->data.sex, "男") == 0 && strcmp(q->data.sex, "女") == 0) return 1;//前男后女
	else if (strcmp(p->data.sex, "女") == 0 && strcmp(q->data.sex, "男") == 0) return 2;//前女后男
	else if (strcmp(p->data.sex, "女") == 0 && strcmp(q->data.sex, "女") == 0) return 3;//均为女
}

//关系的查询
void InquireRelationship(CSTree T) {
	printf("请输入您要查询的成员的姓名:");
	char name[20] = { 0 };
	rewind(stdin);
	scanf_s("%s", &name, 20);
	CSTree member = Search(T, name);
	if (!member) {
		printf("家谱中不存在此人,请检查拼写错误\n");
		Prompt(T, "重新输入", "退出",InquireRelationship);
		return;
	}
	system("cls");
	printf("查找成功!!!\n");
up:
	printf("\t\t\t\t\t\t\t$ 查询成员关系 $\n\n");
	printf("\t\t\t\t\t\t\t1 # 查询子孙\n");
	printf("\t\t\t\t\t\t\t2 # 查询祖先\n");
	printf("\t\t\t\t\t\t\t3 # 查询堂兄弟\n");
	printf("\t\t\t\t\t\t\t4 # 返回主菜单\n");
	printf("\t\t\t\t\t\t\t0 # 退出\n\n");
	printf("\t\t\t\t\t\t╚-----------------------------╝\n");

	//菜单功能实现
	printf("请输入您要选择的功能:");
	char choice = '0';
	rewind(stdin);
	scanf_s("%c", &choice, 1);
	switch (choice)
	{
	case '1': InquireSons(T, member);
		break;
	case '2':InquireAncestor(T, member);
		break;
	case '3':InquireCousin(T, member);
		break;
	case '4':Menu(T);
		break;
	case '0':return;
	default: {printf("请输入正确的数字!!!\n"); goto up; };
		   break;
	}
	return;
}

//查询子孙
void InquireSons(CSTree T,CSTree t) {
	if (!t->firstChild) {
		printf(" %s不存在子孙\n", t->data.name);
		Prompt(T, "返回", "退出", Menu);
		return;
	}
	system("cls");
	printf(" %s的子孙如下:\n\n", t->data.name);
	SqQueue Q;
	InitQueue_Sq(Q, 20);
	CSTree p = t;
	EnQueue_Sq(Q, p);
	printf(" 姓名\t\t性别\t出生日期\t寿终日期(年龄)\n");
	while (!QueueEmpty_Sq(Q))
	{
		DeQueue_Sq(Q, p);
		if (p != t) {
			PrintMemberMessage(p->data);
			printf("\t\t【%d代】", NodeLevel(t, p->data.name));
			printf("\n");
		}
		p = p->firstChild;
		while (p)
		{
			EnQueue_Sq(Q, p);
			p = p->nextSibling;
		}
	}
	printf("\n");
	Prompt(T, "返回", "退出",Menu);
	return;
}

//查询祖先
void InquireAncestor(CSTree T, CSTree t) {
	LStack S;
	InitStack_LS(S);
	while (T || !StackEmpty_LS(S))
	{
		while (T)
		{
			Push_LS(S, T);
			T = T->firstChild;
		}
		Pop_LS(S, T);//STL要求这样做的
		if (T == t)  break;
		if (T) T = T->nextSibling;//root可以为空的
	}
	CSTree e;
	if (StackEmpty_LS(S)) {
		printf("家谱中没有%s的祖先\n", t->data.name);
		Prompt(T, "返回", "退出", Menu);
		return;
	}
	system("cls");
	printf(" %s的祖先如下:\n", t->data.name);
	printf(" 姓名\t\t性别\t出生日期\t寿终日期(年龄)\n");
	while (!StackEmpty_LS(S))
	{
		Pop_LS(S, e);
		PrintMemberMessage(e->data);
		printf("\n");
	}
	printf("\n");
	Prompt(T, "返回", "退出", Menu);
	return;
}

//查询堂兄弟
void InquireCousin(CSTree T, CSTree t){
	int i = NodeLevel(T, t->data.name);
	SqQueue Q;
	InitQueue_Sq(Q, 20);
	CSTree p = T;
	EnQueue_Sq(Q, p);
	while (!QueueEmpty_Sq(Q))
	{
		if (NodeLevel(T, Q.elem[Q.front]->data.name) == i) break;
		DeQueue_Sq(Q, p);
		p = p->firstChild;
		while (p)
		{
			EnQueue_Sq(Q, p);
			p = p->nextSibling;
		}
	}
	if (QueueEmpty_Sq(Q)) {
		printf("%s不存在堂兄弟\n", t->data.name);
		Prompt(T, "返回", "退出", Menu);
		return;
	}
	CSTree e;
	system("cls");
	printf(" %s的堂兄弟如下:\n", t->data.name);
	printf(" 姓名\t\t性别\t出生日期\t寿终日期(年龄)\n");
	while (!QueueEmpty_Sq(Q)) {
		DeQueue_Sq(Q, e);
		if (IsCollateralRelationship(T, t, e)&&IsCollateralRelationship(T, e, t)) {
			if (t != e) {
				PrintMemberMessage(e->data);
				printf("\n");
			}
		}
	}
	Prompt(T, "返回", "退出", Menu);
	return;
}

//将树打印为家谱树结构
void PrintAsTree(CSTree b)
{
	CSTree stack[20], p;          //stack[top]为指针数组 
	int level[20], top, i, n;
	//top为stack栈指针、levle[20]为结点层次数组
	system("cls");
	if (b != NULL)
	{
		top = 1;
		stack[top] = b->firstChild;        //根节点入栈
		level[top] = 0;
		printf("\t\t\t\t\t    ╔------------------------------------╗\n");
		printf("\t\t\t\t\t\t\t  $ 家谱树 $\n\n");
		printf("\t\t\t\t\t\t%s\n", b->data.name);
		while (top > 0)        //栈不为空时,循环继续 
		{
			p = stack[top];        //退栈并凹入显示该节点值
			n = level[top];
			//如果要打印空格则先打印|
			for (i = 1; i < n; i++) {
					//n为输出的空格数 
					if (i == 1) printf("\t\t\t\t\t\t");
					printf("|");
					printf("      ");
			}
			if (NodeLevel(b, p->data.name) == 1) printf("\t\t\t\t\t\t");
			printf("|—>%s\n", p->data.name);
			top--;                     //根节点出栈

			if (p->nextSibling != NULL)
			{
				top++;
				stack[top] = p->nextSibling;          //将兄弟节点入栈 
				level[top] = NodeLevel(b, p->nextSibling->data.name);//计算结点层次
			}
			if (p->firstChild != NULL)
			{

				top++;
				stack[top] = p->firstChild;          //将孩子节点入栈 
				level[top] = NodeLevel(b, p->firstChild->data.name);
			}
		}
	}
	printf("\n\t\t\t\t\t     ╚------------------------------------╝\n");
	Prompt(b, "返回", "退出", Menu);
}

//菜单函数
void Menu(CSTree T) {
	system("cls");
	//菜单界面
	printf("\t\t\t\t\t\t\t$ 家谱管理系统 $\n\n");
	printf("\t\t\t\t\t\t\t1 # 显示家谱成员\n");
	printf("\t\t\t\t\t\t\t2 # 查找家谱成员\n");
	printf("\t\t\t\t\t\t\t3 # 修改家谱成员\n");
	printf("\t\t\t\t\t\t\t4 # 添加家谱成员\n");
	printf("\t\t\t\t\t\t\t5 # 删除家谱成员\n");
	printf("\t\t\t\t\t\t\t6 # 统计家谱成员\n");
	printf("\t\t\t\t\t\t\t7 # 家谱成员关系\n");
	printf("\t\t\t\t\t\t\t8 # 显示关系成员\n");
	printf("\t\t\t\t\t\t\t9 # 显示家谱树\n");
	printf("\t\t\t\t\t\t\t0 # 退出\n\n");
	printf("\t\t\t\t\t\t╚-----------------------------╝\n");

	//菜单选项
	printf("请输入您要选择的功能:");
	char choice = '0';
	rewind(stdin);
	scanf_s("%c", &choice, 1);
	switch (choice)
	{
	case '1': ShowFamilyMembers(T);
		break;
	case '2':SearchFamilyMember(T);
		break;
	case '3':CascadingMenu(T);
		break;
	case '4':AddMember(T);
		break;
	case '5':DeleteMember(T);
		break;
	case '6':CoutMembers(T);
		break;
	case '7':Members_Relationship(T);
		break;
	case '8':InquireRelationship(T);
		break;
	case '9':PrintAsTree(T);
		break;
	case '0':return;
		break;
	default: {printf("输入有误,请重新输入!!!\n"); Menu(T); };
		break;
	}
	return;
}


main.cpp

#include <stdio.h>
#include<stdlib.h>
#include<stdarg.h>
#include<math.h>
#include<string.h>
#include<time.h>

//公共配置
#include "common.h"

//辅助栈
#include "LStack.h";

//辅助队列
#include "SqQueue.h"

//孩子兄弟树操作
#include "CSTreeOperate.h"

//家谱管理系统操作
#include "GenealogyOperate.h";

int main()
{
	//创建家谱树
	CSTree T;
	CreateFamilyTree(T);
	Menu(T);
    return 0;
}

data.txt

张成荣 男 1879 1959
张雨连 男 1900 1980
张建福 男 1925 2010
张炬彬 男 1950 -2
张炬海 男 1952 -2
张顺源 男 1977 -2
张秉梁 男 2000 -2
张建禄 男 1929 2015
张炬科 男 1949 -2
张长源 男 1980 -2
张建真 男 1930 2010
张建祥 男 1925 2005
张炬旺 男 1952 -2
张涛源 男 1985 -2
张雨兴 男 1900 1969
张雨文 男 1910 2000
张建温 男 1935 2000
张建成 男 1936 2005
张炬法 男 1955 -2
张军源 男 1988 -2
张秉轩 男 2005 -2
张杨源 男 1975 -2
张炬琴 女 1957 -2
张凯源 男 1977 -2
张建旺 男 1940 2020
张炬永 男 1965 -2
张炬胜 男 1970 -2
张瑞源 男 1995 -2
张炬凡 女 1968 -2
张辉源 男 1998 -2
张炬其 男 1973 -2
张炬珂 女 1974 -2
张炬杰 男 1980 -2
张建有 男 1935 2005
张炬震 男 1960 -2
张桐源 男 1965 -2
张炬坤 男 1963 -2
张柏源 男 1968 -2

仿照网上的一些资源完成的课程设计,代码仍存在一些问题。

课程设计报告以及全部代码地址:码云

  • 9
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值