BUAA数据结构期末模拟题——查家谱

  • 看前须知
  • 考试回顾
  • 题目内容
    • 问题描述
    • 输入形式
    • 输出形式
    • 样例
    • 样例说明
  • 题解
    • 思考和详解
    • 参考代码
    • 测试数据

看前须知

要点介绍和简要声明.

考试回顾

格式控制输入输出——期中考试模拟题(简单的分类讨论).

标识符的识别(期中考试题)——题目说的不清不楚但其实不难.

空闲空间申请模拟(期中考试题)——注意读题,难度其实一般.

网络打印机选择(北京学院数据结构18级期末压轴题)——伪树状数组(这题杀我)(ಥ_ಥ).

查家谱(士谔书院16级期末)——找最近公共祖先.

图的直径(士谔书院15级期末)——求有向图的最大路径:Floyd的妙用.

题目内容

问题描述

同姓氏中国人见面常说的一句话是“我们五百年前可能是一家”。从当前目录下的文件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。

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

输出形式

所有信息输出到标准输出上。

若要查找的两人不同辈,则先输出辈份低的名字,再输出辈份高的名字,然后输出相差几辈,都以一个空格分隔;

若两人同辈,按照两人名字从标准输入读取的先后顺序,分行输出两人的最近祖先名字、两人姓名以及相差几辈,各数据间以一个空格分隔。

样例

假设当前目录下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

【样例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

样例说明

【样例1说明】

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

【样例2说明】

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

题解

思考和详解

看了一下往年的期末考试题目,最后一题基本都是以树作为压轴题。2016年的查家谱和2018年的网络打印机选择都涉及到的同一个算法——找最近公共祖先,所以必须掌握这个经典算法。在这里还是要说一下的是,这两个题的找最近公共祖先都是简化版的都是给你了每个节点的父亲节点(根节点除外),所以要好好利用好这个条件,让两个节点同时回退到根节点,记录沿路的的信息,然后比对找出第一个相同信息的节点即为最近公共祖先,当然我们必须要思考的是,如果不是这种给了父亲节点的伪线索树,我们又该如何找最近公共祖先呢?

还有一个难点是如何构造树,用递归即可,但是要注意初始化完备,不然会受到野指针的影响!

参考代码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
typedef struct TreeNode {   //树的结构体 char name[200];int depth;                   //新增了层数 struct TreeNode *left;struct TreeNode *right;struct TreeNode *parent;   //新增了父亲节点
}Tree,*Treep;                                            //top是栈顶
int HaveChild_parentNum,depth,chidDepth_1,chidDepth_2,flag,top,i,j;
//  有孩子的父母的个数   深度 第一个孩子的深度 第二个孩子的深度
char parName[200],chidName_1[200],chidName_2[200];
Treep root=NULL,chidPtr_1,chidPtr_2,ancPtr,ptr,path_1[200],path_2[200];
//      第一个孩子的指针 第二个孩子的指针,祖先指针(ancPtr)
void initTree(Treep t, int depth);  //构建树
Treep SearchTree(Treep t,char* s);  //搜索该孩子的位置
Treep FindSameAncestor(Treep p,Treep q);//搜索公共祖先
int main()
{   FILE *fp = fopen("in.txt","r");fscanf(fp,"%d",&HaveChild_parentNum); //读入有孩子的父母的个数for(i=0;i<HaveChild_parentNum;i++){depth=1;     //起始层数是1,不是0 fscanf(fp,"%s %s %s",parName,chidName_1,chidName_2);//录入信息 if(root==NULL){root=(Treep)malloc(sizeof(Tree));            //申请空间 root->left=(Treep)malloc(sizeof(Tree));      //申请空间 root->right=(Treep)malloc(sizeof(Tree)); //申请空间  strcpy(root->name,parName);              strcpy(root->left->name,chidName_1);      //录入信息 root->left->left=root->left->right=NULL;   //一定要初始化好 root->depth=depth,root->left->depth=depth+1;  //录入信息 root->left->parent=root;if(strcmp(chidName_2,"NULL")!=0)   //有没有第二个孩子 {strcpy(root->right->name,chidName_2); //录入信息 root->right->left=root->right->right=NULL; //初始化 root->right->parent=root;  //录入信息 root->right->depth=depth+1;  //录入信息 }    else    root->right=NULL;   //初始化 }else{initTree(root->left,depth+1);   //递归插入 initTree(root->right,depth+1);   //递归插入 }    }scanf("%s %s",chidName_1,chidName_2);flag=0,ptr=NULL;chidPtr_1=SearchTree(root,chidName_1);   //找到第一个人的位置 chidDepth_1=chidPtr_1->depth;flag=0,ptr=NULL;chidPtr_2=SearchTree(root,chidName_2);  //找到第二个人的位置 chidDepth_2=chidPtr_2->depth;if(chidDepth_1 != chidDepth_2)        //层数不同 {if(chidDepth_1 < chidDepth_2)printf("%s %s %d\n",chidName_2,chidName_1,chidDepth_2-chidDepth_1);elseprintf("%s %s %d\n",chidName_1,chidName_2,chidDepth_1-chidDepth_2);}else                             //层数相同 {ancPtr=FindSameAncestor(chidPtr_1,chidPtr_2);  //找到公共祖先 printf("%s %s %d\n",ancPtr->name,chidName_1,chidDepth_1-ancPtr->depth);printf("%s %s %d\n",ancPtr->name,chidName_2,chidDepth_2-ancPtr->depth);}return 0;
}
Treep FindSameAncestor(Treep p,Treep q)
{flag=0;ptr=chidPtr_1,top=0;while(ptr!=root)    //回退祖先,记录沿路的指针地址 {path_1[top]=ptr;  //用栈存下 ptr=ptr->parent,top++;}path_1[top]=root;ptr=chidPtr_2,top=0;while(ptr!=root)   //回退祖先,记录沿路的指针地址 {path_2[top]=ptr;  //用栈存下ptr=ptr->parent,top++;}path_2[top]=root;for(i=0;path_1[i];i++)      //找第一个相同的指针地址即为最近公共祖先的地址 {for(j=0;path_2[j];j++){if(path_1[i]==path_2[j])  //找到 flag=1;if(flag==1)break;}if(flag==1)break;}return path_1[i];  //返回最近公共祖先的指针
}
void initTree(Treep t, int depth)   //插入树,跟之前一样
{if(t==NULL)  return;if(strcmp(t->name,parName)==0)  {t->left=(Treep)malloc(sizeof(Tree));t->right=(Treep)malloc(sizeof(Tree));strcpy(t->left->name,chidName_1);t->left->left=t->left->right=NULL;t->left->depth=depth+1;t->left->parent=t;if(strcmp(chidName_2,"NULL")!=0){strcpy(t->right->name,chidName_2);t->right->left=t->right->right=NULL;t->right->parent=t;t->right->depth=depth+1;}  else    t->right=NULL;}else{initTree(t->left,depth+1);  //递归时层数+1 initTree(t->right,depth+1);  //递归时层数+1 }
}
Treep SearchTree(Treep t,char* s)
{if(t==NULL && flag==0) return NULL;    //还没找着所以递归回退NULL else if (t==NULL && flag==1)   return ptr; //找着了所以返回指针 if(strcmp(t->name,s)==0)   //找到了 {flag=1;ptr=t;return ptr;           //返回该姓名的指针 }    else{SearchTree(t->left,s); //左子树找 SearchTree(t->right,s);//右子树找 }
}

测试数据

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

21
a b c
b d NULL
d f NULL
f h l
h j NULL
j p NULL
p q NULL
l m NULL
m n NULL
n o NULL
c e NULL
e g NULL
g i NULL
i k NULL
k r s
r t NULL
t u v
u w NULL
w x NULL
x y NULL
y z NULL

【测试点1的输入输出】

a z
z a 12

【测试点2的输入输出】

v e
v e 6

【测试点3的输入输出】

o q
f o 4
f q 4

【测试点3的输入输出】

q t
a q 7
a t 7

BUAA(2021春)查家谱(士谔书院16级期末)——找最近公共祖先(已上传测试数据和代码)相关推荐

  1. BUAA(2021春)空闲空间合并(期末考试模拟题)——结构体二级排序

    BUAA数据结构期末模拟题--空闲空间合并 看前须知 考试回顾 题目内容 问题描述 输入形式 输出形式 样例 样例说明 题解 思考和详解 参考代码 看前须知 要点介绍和简要声明. 考试回顾 格式控制输 ...

  2. 在线html差错,易查分在线编辑功能:发现错误随时修改,不用再重新上传表格!

    原标题:易查分在线编辑功能:发现错误随时修改,不用再重新上传表格!

  3. BUAA(2021春)实验:树的构造与遍历——根据提示循序渐进(可惜提示有问题Ծ‸Ծ)

    BUAA数据结构第五次编程题 --实验:树的构造与遍历 看前须知 第五次上机题汇总 实验目的与要求 实验内容 Huffman编码文件压缩 问题描述 实验准备 实验步骤 [步骤1] [步骤2] [步骤3 ...

  4. BUAA(2021春)大作业—— 文本摘要生成(数组字典树+快排=0.087s)

    BUAA数据结构大作业-- 文本摘要生成 看前须知 题目内容 问题描述 输入形式 输出形式 样例 样例说明 题解 思考和详解 参考代码 看前须知 要点介绍和简要声明. 题目内容 问题描述 在自然语言文 ...

  5. BUAA(2021春)小型图书管理系统

    BUAA数据结构第二次编程题--小型图书管理系统 看前须知 第二次上机题汇总 题目内容 问题描述 输入形式 输出形式 样例 样例说明 题解 易错点和难点 参考代码 补充测试的数据 推荐题单 看前须知 ...

  6. BUAA(2021春)文件加密(环)——要求循环链表熟练的删除操作

    BUAA数据结构第三次编程题--文件加密(环) 看前须知 第三次上机题汇总 题目内容 问题描述(建议用链表实现) 输入形式 输出形式 样例 样例说明 题解 易错点和难点 参考代码 补充测试的数据 看前 ...

  7. BUAA(2021春)多项式相乘

    BUAA数据结构第三次编程题--多项式相乘 看前须知 第三次上机题汇总 题目内容 问题描述 输入形式 输出形式 样例 样例说明 题解 易错点和难点 参考代码 补充测试的数据 看前须知 要点介绍和简要声 ...

  8. BUAA(2021春)机试检测异常(简)(期末考试题)——简单排序

    BUAA数据结构期末考试题--机试检测异常(简) 看前须知 题目内容 问题描述 输入形式 输出形式 样例 样例说明 题解 思路详解 参考代码 补充测试的数据 看前须知 要点介绍和简要声明. 题目内容 ...

  9. BUAA(2021春)空闲空间申请模拟(期中考试题)——注意读题,难度其实一般

    BUAA数据结构期中考试题--空闲空间申请模拟 看前须知 题目内容 问题描述 输入形式 输出形式 样例 样例说明 题解 笔者的抱怨和思路详解 参考代码 补充测试的数据 看前须知 要点介绍和简要声明. ...

最新文章

  1. mongodb 复制集 维护小结
  2. python网络爬虫 - 如何伪装逃过反爬虫程序
  3. Coroutine in Java - Quasar Fiber实现--转载
  4. MySql中怎样使用case-when实现判断查询结果返回
  5. dummy.php 下载,internal dummy connection
  6. 性能测试基本流程介绍(《软件性能测试过程详解与安全剖析》)
  7. js html 导出word 不用activexobject,javascript下用ActiveXObject控件替换word书签,将内容导出到word后打印第2/2页...
  8. thinkphp5记录
  9. java cache-control_详解浏览器Cache-Control缓存策略
  10. Android屏幕旋转时Activity不重新调用onCreate的方法
  11. LaTex在Linux下编写高质量的文档
  12. 【KDD20】图神经网络在生物医药领域的应用
  13. 关于CAN网络管理状态
  14. win7台式计算机型号怎么查,教您电脑主板型号怎么看
  15. 用html语言制作表白动画,抖音很火的卡通做我女朋友表白html源码
  16. 【Python安装系统】win10系统从零开始安装Python并为不同项目设置开发环境——以安装TensorFlow2为例
  17. poi对word读取(文本和图片)、修改、保存操作及word转换为PDF
  18. 有关OLE对象的使用(1)
  19. linux shell 关机,linux shell关机命令详解
  20. 红米是个失败,雷军是个笨蛋

热门文章

  1. 什么是fail safe IO
  2. C语言中的语法错误和语义错误
  3. 两台电脑共享鼠标键盘
  4. OpenCV轮廓最大内接矩形(带角度)-计算与绘制(Python / C++源码)
  5. Visual FoxPro 6.0常用命令
  6. 三菱服务器绝对位置,绝对位置控制指令
  7. 多队列网卡及RPS/RFS/XPS设置
  8. 【头歌C语言程序与设计】结构体
  9. echarts 水滴图 去掉波浪阴影
  10. 基础拓扑学笔记(3)——连续映像