北航研究生复试2017上机第三题:二叉树的创建、遍历

本文介绍了北航研究生复试2017年上机试题中关于二叉树的应用。题目要求根据输入的家谱成员信息构建二叉树,并查找两个成员之间的关系,包括最近共同祖先及层次差。示例输入和输出展示了具体的操作过程。
摘要由CSDN通过智能技术生成

题目:输入若干行,每一行的第一个输入为家谱中的某个成员,该行接着输入的信息为每个孩子姓名。
最后一行的输入为要求查找的两个家谱成员的关系。
要求,根据输入的家谱成员的信息,建立二叉树家谱关系图,并输出二位待查找成员在家谱中的关系,包括输出他们最近邻的共同祖先以及在家谱中相差的层次数。

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

#define NAMESIZE 20

typedef struct TreeNode{
    char name[NAMESIZE];        //自己的名字
    int gradation;              //自己的辈分 即树的深度
    char parent[NAMESIZE];      //祖先的名字
    TreeNode* leftchild;        //左孩子
    TreeNode* rightchild;       //右孩子
}TreeNode;

void GetName(char* str, int index, char* parent, char* leftc, char* rightc);        //根据字符串划分各个人的名字
TreeNode* AddTreeNode(TreeNode* root, char* parent, char* leftc, char* right);      //往树中添加节点
TreeNode* FindTreeNode(TreeNode* root, char* parent);                               //根据名字查找树节点
bool IsSame(char* a, char* b);                                                      //判断两个字符串是否相同
void FindRelation(TreeNode* root, char* person1, char *person2);                    //找两个人的关系

int main(){
    TreeNode* root = NULL;
    char ch;
    int tag = 0;
    char parent[NAMESIZE], leftc[NAMESIZE], rightc[NAMESIZE];   //存储每行中输入的父母,孩子
    while( tag == 0 && (ch = getchar()) != EOF ){
        parent[0] = leftc[0] = rightc[0] = '\0';
        char str[3 * NAMESIZE];                                 //存储一行的字符串
        int index = 0;
        while(ch != '\n'){
            str[index++] = ch;
            ch = getchar();
        }
        str[index] = '\0';
        //printf("%s\n", str);
        GetName(str, index, parent, leftc, rightc);             //将一行字符串分解为父母,孩子
        //printf("%s\t%s\t%s\n", parent,leftc, rightc);
        if(strlen(rightc))                                      //如果只输入两个人,就找关系,三个人就添加到树中
            root = AddTreeNode(root, parent, leftc, rightc);    //将新节点加入二叉树中
        else{
            FindRelation(root, parent, leftc);                  //找关系
            tag = 1;
        }
    }

    return 0;
}

void GetName(char* str, int index, char* parent, char* leftc, char* rightc){
    int i;
    int tag = 0;
    for(i = 0; i < index; ){
        while(str[i] == ' ')        //跳过多个空格
            ++i;
        while(str[i] != ' ')
            parent[tag++] = str[i++];   //祖先
        parent[tag] = '\0';

        tag = 0;
        while(str[i] == ' ')        //跳过多个空格
            ++i;
        while(str[i] != ' ' && i < index)
            leftc[tag++] = str[i++];    //左孩子
        leftc[tag] = '\0';

        tag = 0;
        while(str[i] == ' ')        //跳过多个空格
            ++i;
        while(str[i] != ' ' && i < index)
            rightc[tag++] = str[i++];   //右孩子
        rightc[tag] = '\0';
    }
}

TreeNode* AddTreeNode(TreeNode* root, char* parent, char* leftc, char* right){
    if(root == NULL){       //根节点
        root = (TreeNode* )malloc(sizeof(TreeNode));
        strcpy((root->name), parent);
        root->parent[0] = '\0';
        root->gradation = 0;
        root->leftchild = NULL;
        root->rightchild = NULL;
    }

    TreeNode* temp = FindTreeNode(root, parent);
    //printf("%s\n", temp->name);

    TreeNode *lc = (TreeNode* )malloc(sizeof(TreeNode));                
    strcpy((lc->name), leftc);      //创建左孩子
    strcpy(lc->parent,parent);
    lc->gradation = temp->gradation + 1;
    lc->leftchild = NULL;
    lc->rightchild = NULL;

    TreeNode *rc = (TreeNode* )malloc(sizeof(TreeNode));
    strcpy(rc->name, right);        //创建右孩子
    strcpy(rc->parent,parent);
    rc->gradation = temp->gradation + 1;
    rc->leftchild = NULL;
    rc->rightchild = NULL;

    temp->leftchild  = lc;      //连接
    temp->rightchild = rc;

    return root;
}


TreeNode* FindTreeNode(TreeNode* root, char* parent){   //先序遍历 查找name为parent的树节点
    if(root == NULL)    
        return NULL;
    if(IsSame(root->name, parent)){
        return root;
    }
    TreeNode* result = FindTreeNode(root->leftchild, parent);
    if(result == NULL)
        result = FindTreeNode(root->rightchild, parent);
    return result;
}

bool IsSame(char* a, char* b){                          //判断两个字符串是否相同
    int len1 = strlen(a);
    int len2 = strlen(b);
    if(len1 != len2)
        return false;
    for(int i = 0; i < len1; i++)
        if(a[i] != b[i])
            return false;
    return true;
}

void FindRelation(TreeNode* root, char* person1, char *person2){    //找两个人的关系
    TreeNode* p1 = FindTreeNode(root, person1);
    TreeNode* p2 = FindTreeNode(root, person2);

    TreeNode* min;
    TreeNode* max;
    if(p1->gradation > p2->gradation){  //p1的层次更深,辈分更小
        min = p1; max = p2;
    }else{
        min = p2; max = p1;         
    }

    int level = min->gradation - max->gradation;    //小辈分(高层次) - 高辈分(低层次)
    while(min->gradation > max->gradation){         //当两个人辈分不一样时,小辈分向上'爬'
        char *parent = min->parent;                 //直到两个 人辈分(层次)一样
        min = FindTreeNode(root, parent);
    }
    while( !IsSame(min->parent, max->parent) ){     //两个人层次一样时,如果祖先不一样,则处于不同的子树中
        char *parent = min->parent;                 //两个都需要同时向上'爬',直到祖先一样,或者'爬'到根节点
        min = FindTreeNode(root, parent);
        parent = max->parent;
        max = FindTreeNode(root, parent);
    }
    if(min->gradation == 0)
        printf("没有共同祖先 %d\n", level);
    else
        printf("%s %d\n", min->parent, level);

}

输入:
Ye Shu Ba
Shu Ge Mei1
Ba Self Mei2
Ge Son1 Son2
Son2 Mei1

Ye Shu Ba
Shu Ge Mei1
Ba Self Mei2
Ge Son1 Son2
Mei2 Mei1

Ye Shu Ba
Shu Ge Mei1
Ba Self Mei2
Ge Son1 Son2
Ye Mei1

输出
这里写图片描述

这里写图片描述

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值