Family Tree Management System (C language version)

Family Tree Management System

1. Functional frame diagram of this programinsert image description here

2. System function

(1) File operation functions: record input, record output, initialization: the user can create a family tree and save it in the file. In subsequent operations, family tree information can be read from the file, new family members can be added, existing family members can be modified, and existing family members can be deleted. After the operation is completed, it can be saved in a file.
(2) Family tree operation function: output family tree, and can search someone's spouse, all children, all ancestors and other functions.

Three. System function module design:

一.问题描述 

The main problem of this course design is to choose a data structure to describe the relationship between family members in the family tree, add some operations to this data structure, and select specific algorithms to realize the functions of family tree operations and file operations.
two. Basic requirements
Design requirements: Write a program that uses a binary tree to represent a family tree relationship.
Specific requirements:
(1) File operation functions: record input, record output, save family tree records.
(2) Genealogy operation function: output the family tree, and can search for someone's spouse, all sons of a person, and all ancestors of a person.

Four. outline design

1. Data structure design
In the genealogy course design, a binary tree is used to represent the family tree relationship. Since each family member has more than one child and only one parent in the family tree, a binary tree structure is used to describe the relationship between family members. Singly linked lists are also used in the design of family tree courses. In the design, the binary tree should be stored in the file, and finally the records in the file should be read, and the data in the file should be restored to the memory to form a binary tree structure. The elements in the file and The structure between elements is linear, and it is inconvenient to directly operate on the data in the file, so the elements in the file are stored in a single-linked list, and then the operations on the single-linked list are restored to a binary tree in memory.
In the file operation of the family tree, in order to restore the family tree conveniently, the information of each node in the binary tree is saved in the order of layer traversal. In the layer traversal, the queue is used to realize the layer traversal of the binary tree.
2. Algorithm design
This design is mainly divided into two modules as a whole, which are the genealogy operation module and the file operation module.

5. Source code

#define _CRT_SECURE_NO_WARNINGS 1
#pragma warning(disable:6031)
#pragma warning(disable:6011)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <assert.h>

/*字符串最大长度*/
#define STR_LEN 128
/*最大孩子数*/
#define CHILD_LEN 64
/*缓存容量*/
#define BUFFER_SIZE 1024

/*家谱成员信息*/
typedef struct _tMember {
    
    
    char name[STR_LEN];      /*姓名*/
    char wife[STR_LEN];      /*妻子*/
}Member, * pMember;

/*家谱树节点*/
typedef struct _tTreeNode {
    
    
    Member member;                              /*成员信息*/
    struct _tTreeNode* parent;                  /*父节点*/
    struct _tTreeNode* children[CHILD_LEN];     /*孩子节点*/
    int count;                                  /*孩子数量*/
    int level;                                  /*节点层级*/
}TreeNode, * pTreeNode;

/*创建树节点*/
pTreeNode createTreeNode(pTreeNode parent, pMember member) {
    
    
    pTreeNode node = (pTreeNode)calloc(1, sizeof(TreeNode));
    if (node) {
    
    
        node->member = *member;
        if (parent) {
    
    
            node->parent = parent;
            node->level = parent->level + 1;
            parent->children[parent->count++] = node;
        }
    }
    return node;
}

/*删除树节点*/
void removeTreeNode(pTreeNode cursor) {
    
    
    if (cursor) {
    
    
        if (cursor->parent) {
    
    
            pTreeNode parent = cursor->parent;
            int position = -1;
            for (int index = 0; index < parent->count; ++index) {
    
    
                if (parent->children[index] == cursor) {
    
    
                    position = index;
                    break;
                }
            }
            if (position != -1) {
    
    
                for (int index = position + 1; index < parent->count; ++index) {
    
    
                    parent->children[index - 1] = parent->children[index];
                }
                --parent->count;
            }
        }
    }
}

/*计算成员层级*/
int countMemberLevel(const char content[]) {
    
    
    int level = 0;
    const char* cursor = content;
    while (*cursor == ' ') {
    
    
        ++level;
        ++cursor;
    }
    return level;
}

/*输入性别*/
void inputSex(char sex[]) {
    
    
    do {
    
    
        int option;
        printf("\n");
        printf("----------\n");
        printf(" 1 男\n");
        printf(" 2 女\n");
        printf("----------\n");
        printf("     请选择:");
        scanf("%d", &option);
        switch (option) {
    
    
        case 1:
            strcpy(sex, "男");
            return;
        case 2:
            strcpy(sex, "女");
            return;
        }
    } while (1);
}

/*检测日期(yyyy-mm-dd)*/
int checkDate(const char date[]) {
    
    
    int yyyy, mm, dd;
    if (strlen(date) != 10) return 0;
    if (sscanf(date, "%4d-%2d-%2d", &yyyy, &mm, &dd) != 3) return 0;
    if (yyyy < 1999)return 0;
    if (yyyy >= 3000) return 0;
    if (mm < 1) return 0;
    if (mm > 12) return 0;
    if (dd < 1) return 0;
    if (dd > 31) return 0;
    return 1;
}

/*输入日期*/
void inputDate(char date[]) {
    
    
    do {
    
    
        scanf("%s", date);
        if (checkDate(date)) break;
        printf("格式错误,请重新输入!(yyyy-mm-dd)\n");
    } while (1);
}

/*编辑家谱成员信息*/
void editFamilyMember(pMember member) {
    
    
    printf("╔-----------------------------------------╗\n");
    printf("              $ 编辑家谱成员信息 $\n");
    if (strlen(member->name)) {
    
    
        printf(" 姓名:%s\n", member->name);
    }
    else {
    
    
        printf(" 姓名:");
        scanf("%s", member->name);
    }
    printf(" 妻子:");
    scanf("%s", member->wife);
    printf("╚-----------------------------------------╝\n");
}

/*输出成员标题*/
void showFamilyMemberTitle() {
    
    
    printf(" %-10s", "姓名");
    printf(" %-10s", "妻子");
    printf("\n");
}

/*输出成员信息*/
void showFamilyMember(pMember member, int newline) {
    
    
    printf(" %-10s", member->name);
    printf(" %-10s", member->wife);
    if (newline) {
    
    
        printf("\n");
    }
}

/*递归遍历显示家谱信息*/
void recursiveFamilyTreeNodeShow(pTreeNode cursor, int brother_line[], int flag, int all) {
    
    
    if (cursor) {
    
    
        char generation[STR_LEN] = {
    
     0 };
        if (all) {
    
    
            showFamilyMember(&cursor->member, 0);
        }
        sprintf(generation, "【%d世】", cursor->level + 1);
        printf("%10s", generation);
        if (cursor->level > 0) {
    
    
            for (int index = 0; index < cursor->level - 1; ++index) {
    
    
                if (brother_line[index]) {
    
    
                    printf("   │");
                }
                else {
    
    
                    printf("    ");
                }
            }
            if (flag) {
    
    
                printf("   ├─>");
            }
            else {
    
    
                printf("   └─>");
            }
        }
        printf(" %s %s\n", cursor->member.name, cursor->member.wife);
        for (int index = 0; index < cursor->count; ++index) {
    
    
            int flag = (index < cursor->count - 1);
            if (flag) {
    
    
                brother_line[cursor->level] = 1;
            }
            else {
    
    
                brother_line[cursor->level] = 0;
            }
            pTreeNode child = cursor->children[index];
            recursiveFamilyTreeNodeShow(child, brother_line, flag, all);
        }
        brother_line[cursor->level] = 0;
    }
}

/*递归遍历存储家谱信息*/
void recursiveFamilyTreeNodeSave(pTreeNode cursor, FILE* output) {
    
    
    if (cursor) {
    
    
        if (cursor->level > 0) {
    
    
            char format[STR_LEN] = {
    
     0 };
            sprintf(format, "%%%ds", cursor->level);
            fprintf(output, format, " ");
        }
        fprintf(output, "%s ", cursor->member.name);
        fprintf(output, "%s ", cursor->member.wife);
        fprintf(output, "\n");
        for (int index = 0; index < cursor->count; ++index) {
    
    
            pTreeNode child = cursor->children[index];
            recursiveFamilyTreeNodeSave(child, output);
        }
    }
}

/*递归遍历查询家谱信息*/
pTreeNode recursiveFamilyTreeNodeFind(pTreeNode cursor, const char name[]) {
    
    
    if (cursor) {
    
    
        if (strcmp(cursor->member.name, name) == 0 || strcmp(cursor->member.wife, name) == 0) {
    
    
            return cursor;
        }
        for (int index = 0; index < cursor->count; ++index) {
    
    
            pTreeNode child = cursor->children[index];
            pTreeNode result = recursiveFamilyTreeNodeFind(child, name);
            if (result) {
    
    
                return result;
            }
        }
    }
    return NULL;
}

/*递归遍历计算家谱成员数量信息*/
int recursiveFamilyTreeNodeCount(pTreeNode cursor) {
    
    
    int count = 0;
    if (cursor) {
    
    
        count = 1;
        for (int index = 0; index < cursor->count; ++index) {
    
    
            pTreeNode child = cursor->children[index];
            count += recursiveFamilyTreeNodeCount(child);
        }
    }
    return count;
}

/*递归遍历清空家谱信息*/
void recursiveFamilyTreeNodeClear(pTreeNode cursor) {
    
    
    if (cursor) {
    
    
        for (int index = 0; index < cursor->count; ++index) {
    
    
            pTreeNode child = cursor->children[index];
            recursiveFamilyTreeNodeClear(child);
        }
        free(cursor);
    }
}

/*从文件中加载家谱信息*/
pTreeNode loadFamilyTree() {
    
    
    pTreeNode root = NULL;
    FILE* input = fopen("familytree.txt", "r");
    if (input) {
    
    
        pTreeNode cursor = NULL;
        char buffer[BUFFER_SIZE] = {
    
     0 };
        while (fgets(buffer, sizeof(buffer), input)) {
    
    
            Member member = {
    
     0 };
            if (sscanf(buffer, "%s %s", member.name, member.wife) == 2) {
    
    
                int level = countMemberLevel(buffer);
                if (level == 0) {
    
    
                    assert(root == NULL);
                    root = createTreeNode(NULL, &member);
                    cursor = root;
                }
                else {
    
    
                    int step = level - cursor->level;
                    assert(step <= 1);
                    if (step != 1) {
    
    
                        int count = 0 - step + 1;
                        while (count) {
    
    
                            cursor = cursor->parent;
                            --count;
                        }
                    }
                    cursor = createTreeNode(cursor, &member);
                }
            }
        }
        fclose(input);
    }
    return root;
}

/*将家谱信息存储到文件*/
void saveFamilyTree(pTreeNode root) {
    
    
    FILE* output = fopen("familytree.txt", "w");
    if (output) {
    
    
        recursiveFamilyTreeNodeSave(root, output);
        fclose(output);
    }
}

/*显示家谱信息*/
void showFamilyTree(pTreeNode root, int all) {
    
    
    printf("╔-----------------------------------------╗\n");
    printf("              $ 显示家谱信息 $\n");
    int* brother_line = (int*)calloc(1024, sizeof(int));
    if (all) {
    
    
        showFamilyMemberTitle();
    }
    recursiveFamilyTreeNodeShow(root, brother_line, 0, all);
    free(brother_line);
    printf("╚-----------------------------------------╝\n");
}

/*添加家谱成员*/
void addFamilyTree(pTreeNode* root) {
    
    
    char name[STR_LEN] = {
    
     0 };
    printf("╔-----------------------------------------╗\n");
    printf("              $ 添加家谱成员 $\n");
    printf("  输入新成员姓名:");
    scanf("%s", name);
    if (*root) {
    
    
        if (!recursiveFamilyTreeNodeFind(*root, name)) {
    
    
            pTreeNode target = NULL;
            char parentname[STR_LEN] = {
    
     0 };
            printf("  输入新成员的父亲或者母亲名字(指定关系):");
            scanf("%s", parentname);
            target = recursiveFamilyTreeNodeFind(*root, parentname);
            if (target) {
    
    
                Member member = {
    
     0 };
                strcpy(member.name, name);
                editFamilyMember(&member);
                createTreeNode(target, &member);
                saveFamilyTree(*root);
                showFamilyMemberTitle();
                showFamilyMember(&member, 1);
                printf("----------------\n");
                printf("成功添加以上家谱成员!\n");
            }
            else {
    
    
                printf("添加失败,家谱中未找到该名字!\n");
            }
        }
        else {
    
    
            printf("添加失败,该成员名称已经存在!\n");
        }
    }
    else {
    
    
        Member member = {
    
     0 };
        strcpy(member.name, name);
        editFamilyMember(&member);
        *root = createTreeNode(NULL, &member);
        saveFamilyTree(*root);
        showFamilyMemberTitle();
        showFamilyMember(&member, 1);
        printf("----------------\n");
        printf("成功添加以上家谱成员!\n");
    }
    printf("╚-----------------------------------------╝\n");
}

/*删除家谱成员*/
void removeFamilyTree(pTreeNode* root) {
    
    
    pTreeNode target = NULL;
    char name[STR_LEN] = {
    
     0 };
    printf("╔-----------------------------------------╗\n");
    printf("              $ 删除家谱成员 $\n");
    printf("  输入姓名:");
    scanf("%s", name);
    target = recursiveFamilyTreeNodeFind(*root, name);
    if (target) {
    
    
        showFamilyMemberTitle();
        showFamilyMember(&target->member, 1);
        removeTreeNode(target);
        recursiveFamilyTreeNodeClear(target);
        if (target == *root) {
    
    
            *root = NULL;
        }
        saveFamilyTree(*root);
        printf("----------------\n");
        printf("成功删除以上家谱成员!\n");
    }
    else {
    
    
        printf("  没有找到相关信息!\n");
    }
    printf("╚-----------------------------------------╝\n");
}

/*查找家谱成员*/
void findFamilyTree(pTreeNode root) {
    
    
    pTreeNode target = NULL;
    char name[STR_LEN] = {
    
     0 };
    printf("╔-----------------------------------------╗\n");
    printf("              $ 查找家谱成员 $\n");
    printf("  输入姓名:");
    scanf("%s", name);
    target = recursiveFamilyTreeNodeFind(root, name);
    if (target) {
    
    
        int* brother_line = (int*)calloc(1024, sizeof(int));
        printf("---------------\n");
        showFamilyMemberTitle();
        showFamilyMember(&target->member, 1);
        printf("---------------\n");
        printf("【所有孩子】\n");
        recursiveFamilyTreeNodeShow(target, brother_line, 0, 0);
        free(brother_line);
        printf("【所有祖先】\n");
        showFamilyMemberTitle();
        while (target->parent) {
    
    
            target = target->parent;
            showFamilyMember(&target->member, 1);
        }
    }
    else {
    
    
        printf("  没有找到相关信息!\n");
    }
    printf("╚-----------------------------------------╝\n");
}

/*修改家谱成员*/
void modifyFamilyTree(pTreeNode root) {
    
    
    pTreeNode target = NULL;
    char name[STR_LEN] = {
    
     0 };
    printf("╔-----------------------------------------╗\n");
    printf("              $ 修改家谱成员 $\n");
    printf("  输入姓名:");
    scanf("%s", name);
    target = recursiveFamilyTreeNodeFind(root, name);
    if (target) {
    
    
        showFamilyMemberTitle();
        showFamilyMember(&target->member, 1);
        printf("----------------\n");
        editFamilyMember(&target->member);
        printf("----------------\n");
        saveFamilyTree(root);
        printf("成功修改以上家谱成员!\n");
    }
    else {
    
    
        printf("  没有找到相关信息!\n");
    }
    printf("╚-----------------------------------------╝\n");
}

/*统计家谱成员*/
void statFamilyTree(pTreeNode root) {
    
    
    int count = recursiveFamilyTreeNodeCount(root);
    printf("╔-----------------------------------------╗\n");
    printf("              $ 统计家谱成员 $\n");
    printf("  成员数量:%d\n", count);
    printf("╚-----------------------------------------╝\n");
}

/*菜单操作*/
void menuOptions(pTreeNode root) {
    
    
    system("title 家族谱管理系统");
    while (1) {
    
    
        int option = 0;
        printf("╔-----------------------------------------╗\n");
        printf("              $ 家族谱管理系统 $\n");
        printf("  1 # 显示家谱(精简)\n");
        printf("  2 # 显示家谱(完整)\n");
        printf("  3 # 添加家谱成员\n");
        printf("  4 # 删除家谱成员\n");
        printf("  5 # 查找家谱成员\n");
        printf("  6 # 修改家谱成员\n");
        printf("  7 # 统计家谱成员\n");
        printf("  0 # 退出\n");
        printf("╚-----------------------------------------╝\n");
        printf("     请选择:");
        scanf("%d", &option);
        if (option == 0) break;
        switch (option) {
    
    
        case 1:
            showFamilyTree(root, 0);
            break;
        case 2:
            showFamilyTree(root, 1);
            break;
        case 3:
            addFamilyTree(&root);
            break;
        case 4:
            removeFamilyTree(&root);
            break;
        case 5:
            findFamilyTree(root);
            break;
        case 6:
            modifyFamilyTree(root);
            break;
        case 7:
            statFamilyTree(root);
            break;
        }
    }
}

/*主函数*/
int main() {
    
    
    /*从文件加载家谱信息*/
    pTreeNode root = loadFamilyTree();
    if (root) {
    
    
        /*进入操作菜单*/
        menuOptions(root);
        /*释放家谱树*/
        recursiveFamilyTreeNodeClear(root);
    }
    return 0;
}

6. Brief description of debugging and operation

The two modules included in this program, file operation and family tree operation function module, basically realize the input of family tree records, read saved records, clear family tree saved records, add members, save files, modify family tree member information, and delete family tree members. People record, look up someone's children, look up someone's ancestors, output family tree, etc. But this system still has a shortcoming, if there is no family tree information in the file, the system will not be able to open normally

Guess you like

Origin blog.csdn.net/m0_73804085/article/details/128461969