c语言实现家谱(孩子兄弟树)数据结构

一、需求分析

(一)题目

【问题描述】
家谱记载了一个家族的世系繁衍及重要人物事迹。使用树型结构对家谱进行管理,实现查看祖先和子孙个人信息,插入家族成员,删除家族成员的功能
【基本要求】
(1)采用树形结构完成对家谱成员信息的建立,可利用孩子兄弟表示方法表示树型结构
(2)完成家谱成员信息查找、插入、修改、删除功能
(3)判断两个人的家族关系
(4)进行子孙、祖先、堂兄弟关系的查询
【拓展要求】
(1)实现树的层次遍历,显示家族每一代的成员
(2)打印家谱的树型结构操作
(3)判断两个成员是否属于直系或旁系三代关系
(4)自行设计家谱的其他操作

(二)程序所能达到的功能;

1—插入新人物

1.输入的形式:
例:姓名 性别(1/0) 配偶姓名 生日 生存状况(1/0) 父亲姓名
%s %d %s %d %d %s
姓名,父亲姓名,配偶姓名无输入值范围 性别和生存状况输入值范围为1/0 ,生日输入值范围为0~2021
2. 输出的形式:控制台打印函数的操作结果
3.测试数据:
正确输入:刘星 1 无 1999 1 贾政
正确输出:插入成功
错误输入1:刘星 2 无 1999 1 贾政
错误输出1:性别有误
错误输入2:刘星 1 无 2022 1 贾政
错误输出2:生日有误
错误输入3:刘星 1 无 1999 2 贾政
错误输出3:生存状况有误
错误输入4:刘星 1 无 1999 1 刘六
错误输出4:你的父亲不在家谱里
错误输入5:刘星 1 无 1 1 贾政
错误输出5:你的生日不能比父亲早

2—删除人物

1.输入的形式:
姓名,%s,输入无限制
2.输出的形式;控制台打印函数的操作结果
测试数据:贾政
测试结果:贾政和贾政的后代都从家谱中消失了

3—修改人物信息

1.输入的形式和输入值的范围:无
2. 输出的形式;把函数执行结果打印在控制台上
3.测试数据:贾宝玉
A.修改姓名为贾王 成功
b修改生存状况为0/1成功 2失败
c修改生日 0~2021为有效输入
d修改配偶名:无限制输入值的类型
E 修改性别

4—查找人物

输入:贾宝玉
输出:查找成功

5–人物关系查询

输入:贾宝玉

6—判断两人关系

输入:贾宝玉 贾政
输出:父子

7—凹入表方式打印树状家谱

1.输入的形式和输入值的范围:无
2. 输出的形式;凹入表方式打印家谱

8—层次遍历家谱

1.输入的形式和输入值的范围:无
2. 输出的形式;层次遍历家谱

二、概要设计

(一)数据类型的定义

决定采用孩子兄弟二叉树来表示家谱。
家谱可以看作是一颗树。许多家庭看作一片森林。每个森林都有唯一对应的二叉树。且二叉树非常方便操作和理解。下图演示了树转换为二叉树的过程。
在这里插入图片描述

所以需要定义以下几种数据类型:
1.CSTree 节点。传统一般定义为

typedef struct CSTNode
{
   
    Elemtype data;
    struct CSTNode *firstChild,*nextSibling;
}CSTNode;

但是由于本程序要实现的是家谱,所以添加指向父亲节点的指针是非常有必要的,可以让程序变得更加简便。
2.CSTree节点的数据域
需要包括人物的一系列信息。配偶,生日,姓名,性别,辈分,生存情况等
3.队列节点
在层次遍历家谱的时候会用到

(二)主程序的流程

打开程序,首先初始化,读取文件内容在程序里自动生成一个孩子兄弟树。在主菜单中,可以选择需要的操作模块,每个模块执行完后又回到菜单界面,直到用户选择退出。如图所示。
在这里插入图片描述

(三)各程序模块之间的调用关系。

本程序只含有两个模块。一个是主程序main.C,一个是孩子兄弟树的基本操作实现CSTree。主程序模块调用基本操作模块。

在这里插入图片描述

三、详细设计

(一)数据类型定义实现

族谱规则
族谱只会跟踪记录男性以及男性的后代,对于女性我们只会记录她在何时出嫁,并不记录她的后代,或者说族谱中的人员向上追溯的时候默认追溯的是父亲一支的关系;
逻辑分析
族谱与数据结构中树的概念相结合,每一个节点就是族谱中的个人,于是我们就需要知道每个人最基本的特性,于是就可以抽象化变成树中的属性;

父母 (parent) --人
兄弟 (brother) --人
孩子 (children) --人
姓名 (name) --字符串
生辰八字 (birthday) --日期
性别 (gender) --性别
那么我们对应的树的结构就出来了

1.数据域设计
typedef struct MSG
{
   
    char name[100];//姓名
    int sex;//性别 1为男性 0为女性
    char fed[100];//配偶姓名  
    int seniority;//辈分
    int birth;
    int alive;//1为在世,0为已过世
    
}MSG;
2.兄弟孩子树节点设计
typedef struct CSTNode
{
   
    MSG data;
    struct CSTNode *firstChild,*nextSibling,*father,*mother;
    //mother指针闲置了,后续用不到
}CSTNode,*CSTree,*CSForest;

其他问题
关于孩子的问题
很多人的孩子不止一个,那么我们就会将二儿子/三儿子添加到对应的孩子的brother指针,并且将parent指针指向自己哥哥的父母;

3.返回值设计
typedef enum status{
                
    TRUE,
    FALSE,
    OK,
    ERROR,
    SUCCESS,
    OVERFLOW,
    EMPTY
}Status;//枚举类型返回值
4.队列节点设计
typedef struct LNode{
                  //链表和链表结点类型 
    CSTree data;                     //数据域
    struct LNode *next;             //指针域
}LNode, *LinkList;

(二)基本操作模块代码实现(CSTree.c)

1.创建节点
void createCSTNode(CSTree*A){
   //没问题
    (*A)=(CSTree)malloc(sizeof(CSTNode));
    if((*A)==NULL)return;
    initCSTNode(&(*A));
}

初始化节点数据避免出现野指针等情况

void initCSTNode(CSTree*A){
   // 没问题
    if((*A)==NULL)return;
    (*A)->father=NULL;
    (*A)->mother=NULL;
    (*A)->firstChild=NULL;
    (*A)->nextSibling=NULL;
    (*A)->data.birth=0;
    (*A)->data.seniority=0;
    (*A)->data.sex=0;
    (*A)->data.alive=0;
    strcpy((*A)->data.name,"无");
    strcpy((*A)->data.fed,"无");
    return;
}
2.删除节点函数

思路:
1.如果A是父亲节点的第一个孩子,则让A的兄弟成为父亲节点的第一个孩子
2.否则,找到A的前驱节点指向A的后驱
然后在释放A的空间之前将A的后代全部移除,此处调用Destroy函数

void deleteNode(CSTree *A){
   
    CSTree bro1;
    if((*A)->father->firstChild==(*A)){
   
        (*A)->father->firstChild=(*A)->nextSibling;
    }
    else
    {
   
        for(bro1=(*A)->father->firstChild;bro1->nextSibling!=(*A);){
   
            bro1=bro1->nextSibling;
        }
        bro1->nextSibling=(*A)->nextSibling;
    }
    (*A)->nextSibling=NULL;
    (*A)->father=NULL;
    system("pause");
    destroy(&(*A));
}

销毁函数
思路:和二叉树的销毁一模一样,因为兄弟孩子树就是二叉树

void destroy(CSTree*A){
   
    if((*A)==NULL)return;
    destroy(&((*A)->firstChild));
    destroy(&((*A)->nextSibling));
    free(*A);
}
3.插入函数

参数:父亲节点指针和孩子节点指针
思路:此处要考虑年龄因素,即生日较小的人年龄较大,年龄最大的孩子应该为父亲节点的firstchild。
情况:1.如果father不存在firstchild,直接插入child即可
2如果firstchild年龄比child小,则child成为新的firstchild
3.如果firstchild年龄比child大,则遍历兄弟链表直到找到插入位置为止

void insertNode(CSTree*father,CSTree*child){
   
    (*child)->data.seniority=(*father)->data.seniority+1;
    (*child)->father=(*father);
    int birth=(*child)->data.birth;
    CSTree bro1=(*father)->firstChild;
    if(bro1==NULL){
   
        (*father)->firstChild=(*child);
        return;
    }
    if(bro1->data.birth>=birth){
   
        (*child)->nextSibling=bro1;
        (*father)->firstChild=(*child);
        return;
    }
    CSTree bro2=(*father)->firstChild;
    bro1=bro2->nextSibling;
    for(;bro1!=NULL&&birth>bro1->data.birth;){
   
        bro2=bro2->nextSibling;
        bro1=bro2->nextSibling;
    }
    (*child)->nextSibling=bro1;
    bro2->nextSibling=(*child);

    return;
}
4.查找函数

参数:T为树的结点,name为需要找的人,B储存找到的结点位置
思路:先序遍历

void searchNode(CSForest T,char name[100],CSTree*B){
   
    if(NULL==T)return;
    if(strcmp(T->data.name,name)==0){
   
        (*B)=T;
        return;
    }
    searchNode(T->firstChild,name,&(*B));
    if((*B)!=NULL)return;
    searchNode(T->nextSibling,name,&(*B));
}
5.修改个人信息函数
void changeMsg(CSTree*B,CSForest T){
   
    if((*B)==NULL)return;
    if((*B)->data.seniority==0){
   
  • 48
    点赞
  • 317
    收藏
    觉得还不错? 一键收藏
  • 13
    评论
### 回答1: 在Excel中制作家谱世系图可以方便地展示家族的血脉关系和世代传承。以下是制作家谱世系图的步骤: 1. 创建Excel表格:在Excel中创建一个新的工作表,可以根据需要调整列宽和行高,使表格更加清晰易读。 2. 输入家族成员信息:在表格中逐行输入家族成员的信息,包括姓名、出生日期、婚姻状态等。可以使用不同的列来表示不同的信息。 3. 建立家族关系:在Excel中创建两列用于表示家族成员之间的关系。例如在一列中可以选择配偶的姓名,在另一列中选择子女的姓名,通过这种方式来建立家族成员之间的关联。 4. 添加箭头和线条:为了更直观地表示家族成员之间的关系,可以使用Excel的绘图工具来添加箭头和线条。在合适的位置绘制箭头和线条,将相关家族成员连接起来,形成世系图的结构。 5. 设置格式和样式:为了使家谱世系图更加美观,可以设置不同的格式和样式。可以调整字体的大小、颜色和样式,为家族成员添加插图或照片。 6. 添加图例和注释:为了帮助读者更好地理解世系图,可以在Excel中添加图例和注释。图例可以解释不同的符号或颜色代表的意义,而注释可以提供额外的说明信息。 7. 打印或分享世系图:完成家谱世系图后,可以选择将其打印出来或保存为图片,以便与家族成员分享或用作家族历史记录的一部分。 通过Excel制作家谱世系图可以简洁明了地展示家族的血统关系和世代传承,帮助家族成员更好地了解自己的家族历史和身世。 ### 回答2: Excel是一个非常方便的工具,可以用来制作家谱世系图。首先,我们需要准备好家庭成员的信息,包括姓名、出生日期、婚姻状况等。然后,我们可以在Excel中创建一个表格,每一列代表一个信息字段,每一行代表一个家庭成员。 在表格中,我们可以将姓名放在第一列,出生日期放在第二列,婚姻状况放在第三列。然后,我们可以通过合并单元格的方式来创建分支,以展示家庭的世系关系。例如,合并第四列和第五列的单元格来创建一个夫妻的分支,再合并第六列和第七列的单元格来创建他们的子女分支。 当然,为了使世系图更加清晰易读,我们还可以对表格进行一些美化处理。例如,可以使用不同的颜色来标识不同的世系关系,或者可以在表格的顶部添加一个标题栏,以便更好地显示整个家谱世系图的结构。 除了基本信息外,我们还可以在Excel中添加其他功能,例如计算家庭成员的年龄、计算家族的统计数据等。这些功能可以帮助我们更好地了解家族的历史和发展。 总之,通过使用Excel,我们可以简便地制作家谱世系图。它不仅可以帮助我们记录家族的历史,还可以方便地与他人分享和讨论家族的世系关系。 ### 回答3: Excel是一种功能强大的电子表格软件,可以用来制作家谱世系图。以下是在Excel中制作家谱世系图的步骤: 1. 打开Excel软件并创建一个新的工作表。 2. 在第一行的单元格中输入家谱的最早祖先的姓名,例如“第一代”。 3. 在第二行的单元格中输入第一代祖先的子女的姓名,每个子女姓名占用一个单元格。 4. 在第三行的单元格中输入第二代祖先的子女的姓名,每个子女姓名占用一个单元格。将每个子女姓名与他们的父母对应起来。 5. 依此类推,在下面的行中输入每一代祖先的子女的姓名,每个子女单独占用一个单元格。将子女姓名与他们的父母对应起来。 6. 如果有其他附加信息,如出生日期、婚姻状况等,可以将这些信息输入到每个祖先的行中的相应单元格中。 7. 根据需要,可以进行格式和样式的调整,如设置单元格的颜色、字体和边框等。 8. 如果家谱很庞大,可以使用Excel的筛选功能来过滤特定的子孙后代信息,以便更清晰地展示家谱世系。 9. 最后,保存你的家谱世系图,并根据需要进行打印或分享。 使用Excel制作家谱世系图的好处是,它提供了一个结构化的方式来记录和展示家族成员的信息。同时,Excel的强大计算功能可以用来进行一些统计分析,如计算家族成员的数量、代数关系等。此外,由于Excel是一种常见的电子表格软件,它的使用非常普及,可以方便地与其他人分享和编辑家谱信息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值