每日一算法题-姓氏族谱系统

272 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第29天,点击查看活动详情

一、题目

描述

某一姓氏族谱系统
某一姓氏为了更好的理清各代人的关系传承,想请你为他们做一套族谱关系系统。系统要求:
1,每一个人信息包含姓名,性别,出生年月
2,可先序遍历整个族谱井列出所有的人
3,可添加某一个人进族谱
4,可删除某一个人
5. 给出某一个人,可列出其孩子和双亲

#include <iostream>
#include <vector>
#include <algorithm>
#include <unordered_map>
using namespace std;

int generateId(){
    static int id = 0;
    ++id;
    return id;
}

struct Human{
    Human* dad = nullptr;
    Human* mom = nullptr;
    vector<Human*> children;
    Human(string name, string sex, string born): id(generateId()), name(name), sex(sex), born(born) {}
    int id;
    string name;
    string sex;
    string born;
};

void printAll(int ancestorDad){

}
void add(Human* child, int dad, int mom){

}
void remove(int id){

}
void printOne(int id){

}

int main(int, char*[])
{
    Human ancestorDad("朱元璋", "男", "1328.10");
    Human ancestorMom("孝慈高皇后", "女", "1332.08");

    Human* child1 = new Human("朱标", "男", "1355.10");
    Human* child2 = new Human("吕氏", "女", "1355.11");
    Human* child3 = new Human("朱允炆", "男", "1377.12");

    Human* child4 = new Human("朱棣", "男", "1360.05");
    Human* child5 = new Human("明成祖仁孝皇后", "女", "1362.03");
    Human* child6 = new Human("朱高炽", "男", "1378.08");
    Human* child7 = new Human("诚孝张皇后", "女", "1380.03");
    Human* child8 = new Human("朱瞻基", "男", "1399.03");

    add(&ancestorDad, 0, 0);
    add(&ancestorMom, 0, 0);

    add(child1, ancestorDad.id, ancestorMom.id);
    add(child2, 0, 0);
    add(child3, child1->id, child2->id);

    add(child4, ancestorDad.id, ancestorMom.id);
    add(child5, 0, 0);
    add(child6, child4->id, child5->id);
    add(child7, 0, 0);
    add(child8, child6->id, child7->id);

    printAll(ancestorDad.id);
    remove(child6->id);
    printAll(ancestorDad.id);
    printOne(child4->id);

    return 0;
}

二、分析

由题意可知,姓氏族谱系统和二叉树结构非常像,每个该姓氏节点,除祖父节点外,必定有父母双亲两个节点指向他,不同的是,母亲节点是没有父母双亲节点的,而且父母双亲节点也可能指向多个子女节点,也就是说需要兼容一母多子,一夫多妻的情况。
题中规定要完成添加,删除,打印单个,打印所有四个功能。
添加功能比较简单,按部就班对节点属性进行赋值即可。
删除功能就比较复杂,删除一个节点,要考虑其是父亲节点还是母亲节点,删除父亲节点,就要删除他的所有妻子节点和所有孩子节点,而父亲节点并不直接指向母亲节点。删除母亲节点,要考虑其所有孩子节点。删除孩子节点,要考虑他的母亲节点是否还有孩子,因为没有孩子的母亲节点是不能单独存在于族谱上的。
打印单个功能比较简单,按部就班打印结构属性即可。
打印全部功能比较复杂,要考虑到一夫多妻,一母多子,妻子节点不能二次打印,所以在打印过程中需要加状态。

三、模拟

  1. 朱元璋
  2. 朱标的母节点-孝慈高皇后
  3. 朱标
  4. 朱允炆的母节点-吕氏
  5. 朱允炆
  6. 朱棣
  7. 朱高炽的母节点-明成祖仁孝皇后
  8. 朱高炽
  9. 朱瞻基的母节点-诚孝张皇后
  10. 朱瞻基

四、实现

struct Human{
    Human* dad = nullptr;
    Human* mom = nullptr;
    vector<Human*> children;
    Human(string name, string sex, string born): id(generateId()), name(name), sex(sex), born(born) {}
    int id;
    string name;
    string sex;
    string born;
    bool printed = false;
};

static unordered_map<int, Human*> hashHuman;

void printAllDfs(Human* child){
    if(!child->mom->printed){
        child->mom->printed = true;
        cout << "\n姓名:" << child->mom->name << ",性别:" << child->mom->sex << ",出生年月:" << child->mom->born << endl;
    }
    cout << "\n姓名:" << child->name << ",性别:" << child->sex << ",出生年月:" << child->born << endl;
    for(Human* sun : child->children){
        printAllDfs(sun);
    }
    for(Human* sun : child->children){
        if(sun->mom->printed){
            sun->mom->printed = false;
        }
    }
}
void printAll(int ancestorDad){
    auto iter = hashHuman.find(ancestorDad);
    Human* human = iter->second;
    cout << "\n姓名:" << human->name << ",性别:" << human->sex << ",出生年月:" << human->born << endl;
    for(Human* child : human->children){
        printAllDfs(child);
    }
    for(Human* child : human->children){
        if(child->mom->printed){
            child->mom->printed = false;
        }
    }
}

void add(Human* child, int dad, int mom){
    if(dad != 0){
        auto iter = hashHuman.find(dad);
        Human* dad = iter->second;
        iter = hashHuman.find(mom);
        Human* mom = iter->second;
        child->dad = dad;
        child->mom = mom;
        dad->children.push_back(child);
        mom->children.push_back(child);
    }
    hashHuman.insert(std::pair<int, Human*>(child->id, child));
}
void remove(int id){
    auto iter = hashHuman.find(id);
    Human* human = iter->second;
    if(!human->children.empty()){
        if(human->sex == "女"){
            remove(human->children.at(0)->dad->id);
            return;
        }
        for(Human* child : human->children){
            remove(child->id);
        }
    }
    if(human->dad){
        for(int i = human->dad->children.size() - 1; i >= 0; --i){
            if(human->dad->children.at(i)->id == human->id){
                human->dad->children.erase(std::begin(human->dad->children) + i);
                break;
            }
        }
        for(int i = human->mom->children.size() - 1; i >= 0; --i){
            if(human->mom->children.at(i)->id == human->id){
                human->mom->children.erase(std::begin(human->mom->children) + i);
                break;
            }
        }
        if(human->mom->children.empty()){
            delete human->mom;
        }
    }
    delete human;
}
void printOne(int id){
    auto iter = hashHuman.find(id);
    Human* human = iter->second;
    cout << "\n姓名:" << human->name << ",性别:" << human->sex << ",出生年月:" << human->born << endl;
}

五、结言

族谱系统与常见树结构不同,特定问题,特殊解决。

创作不易,留个赞再走吧!如果对文章内容有任何指正,欢迎评论!