【数据结构】在家谱中查找关系远近

问题描述

同姓氏中国人见面常说的一句话是“我们五百年前可能是一家”。从当前目录下的文件in.txt中读入一家谱,从标准输入读入两个人的名字(两人的名字肯定会在家谱中出现),编程查找判断这两个人相差几辈,若同辈,还要查找两个人共同的最近祖先以及与他(她)们的关系远近。假设输入的家谱中每人最多有两个孩子,例如下图是根据输入形成的一个简单家谱:
在这里插入图片描述
通过该家谱,可以看到wangliang、wangguoping和wangguoan都有两个孩子,wangtian、wangxiang和wangsong有一个孩子,wangguang、wangqinian、wangping和wanglong还没有孩子。若要查找的两个人是wangqinian和wangguoan,从家谱中可以看出两人相差两辈;若要查找的两个人是wangping和wanglong,可以看出两人共同的最近祖先是wangguoan,和两人相差两辈。

输入形式

从当前目录下的in.txt中读入家谱。文件中第一行是家谱中有孩子的人数,后面每行内容是每个人的名字和其孩子的名字,名字都由1到20个英文字母构成,各名字间以一个空格分隔,整个家谱中的人员都不会重名;若只有一个孩子,则第二个孩子的名字为NULL;若没有孩子,则不需输入;输入的顺序是按照辈份从高到低依次输入,若孩子A出现在孩子B之前,则A的孩子应在B的孩子之前输入。假设以该形式读入的家谱肯定能够形成类似上图所示的一棵二叉树形式的家谱,家谱中任何两人相差的辈份不会超过100。

从标准输入读入要查找的两个人的名字,两名字间也以一个空格分隔。

输出形式

所有信息输出到标准输出上。
若要查找的两人不同辈,则先输出辈份低的名字,再输出辈份高的名字,然后输出相差几辈,都以一个空格分隔;
若两人同辈,按照两人名字从标准输入读取的先后顺序,分行输出两人的最近祖先名字、两人姓名以及相差几辈,各数据间以一个空格分隔。

样例1输入

假设当前目录下in.txt文件内容为:

6
wangliang wangguoping wangguoan
wangguoping wangtian wangguang
wangguoan wangxiang wangsong
wangtian wangqinian NULL
wangxiang wangping NULL
wangsong wanglong NULL

从标准输入读取:

wangqinian wangliang

样例1输出

wangqinian wangliang 3

样例1说明

家谱中输入了六个人名及其孩子的人名,形成了“问题描述”中的家谱,要查找的两人是wangqinian和wangliang,wangliang比wangqinian高3辈。

样例2输入

假设当前目录下in.txt文件内容为:

6
wangliang wangguoping wangguoan
wangguoping wangtian wangguang
wangguoan wangxiang wangsong
wangtian wangqinian NULL
wangxiang wangping NULL
wangsong wanglong NULL

从标准输入读取:

wangping wanglong

样例2输出

wangguoan wangping 2
wangguoan wanglong 2

样例2说明

和样例1同样输入了一家谱,wangping和wanglong共同的最近祖先是wangguoan,该祖先与两人相差两辈。

代码

#include<fstream>
#include <iostream>
#include<stdlib.h>
#include<cstring>
#include<stack>
using namespace std;
string str, str1, str2;

typedef struct TreeNode {
    int deep;
    string name;
    TreeNode* parent;
    TreeNode* lchild;
    TreeNode* rchild;

}TreeNode;

TreeNode* T = new TreeNode();

TreeNode* SearchChild(string str, TreeNode* T) {
    if (T->name == str) return T;
    TreeNode* temp = new TreeNode();
    temp->name = "";
    if (T->lchild != NULL) {
        temp = SearchChild(str, T->lchild);
        if (temp->name == str)
            return temp;
    }
    if (T->rchild != NULL) {
        temp = SearchChild(str, T->rchild);
        if (temp->name == str)
            return temp;
    }
    return temp;
}

void InsertNode(TreeNode* T) {
    T->lchild = new TreeNode();
    T->lchild->parent = T;
    T->lchild->name = str1;
    T->lchild->deep = T->deep + 1;
    if (str2 != "NULL") {
        T->rchild = new TreeNode();
        T->rchild->parent = T;
        T->rchild->name = str2;
        T->rchild->deep = T->deep + 1;
    }
    else {
        T->rchild = NULL;
    }
}

void ReadFile(const string file) {
    ifstream fin;
    fin.open("in.txt");
    if (!fin.is_open()) {
        cout << "ERROR";
        exit(100);
    }
    int n;
    fin >> n;
    for (int i = 0; i < n; i++) {
        fin >> str >> str1 >> str2;
        if (i == 0) {
            T->name = str;
            T->parent = NULL;
            T->deep = 1;
        }
        InsertNode(SearchChild(str, T));
    }
    fin.close();
}

void Delete(TreeNode* T) {
    if (T == NULL) return;
    Delete(T->lchild);
    Delete(T->rchild);
    delete(T);
}

TreeNode* FindParent(TreeNode* case1, TreeNode* case2) {
    while (case1->parent != case2->parent) {
        case1 = case1->parent;
        case2 = case2->parent;
    }
    return case1->parent;
}

void Search() {
    cin >> str1 >> str2;
    TreeNode* case1, * case2;
    case1 = SearchChild(str1, T);
    case2 = SearchChild(str2, T);
    if (case1->deep == case2->deep) {
        TreeNode* ancient = FindParent(case1, case2);
        cout << ancient->name << " " << str1 << " " << (case1->deep - ancient->deep) << endl;
        cout << ancient->name << " " << str2 << " " << (case1->deep - ancient->deep) << endl;
    }
    else if (case1->deep > case2->deep) {
        cout << case1->name << " " << case2->name << " " << case1->deep - case2->deep << endl;
    }
    else {
        cout << case2->name << " " << case1->name << " " << case2->deep - case1->deep << endl;
    }
}

int main()
{
    ReadFile("in.txt");
    Search();
    Delete(T);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值