【问题描述】
同姓氏中国人见面常说的一句话是“我们五百年前可能是一家”。从当前目录下的文件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
#include
#include
#define M 100
typedef struct node{
char name[200];
int depth;
struct node *lchild, *rchild, *par; //这里增加一个指向 “爸爸”的节点,以便后续找祖先回溯使用
}BTNode, *BTREE;
BTREE find(BTREE root, char who[]) /*用中序遍历找某个人 using inorder*/
{
BTREE STACK[M], T = root;
int top = -1;
if(root != NULL)
{
do{
while(T != NULL){
STACK[++top] = T;
T = T->lchild;
}
T = STACK[top--];
if( strcmp(who, T->name) == 0 )
{
return T;
}
T = T->rchild;
}while( !(T==NULL && top == -1) );
}
}
int layer1, layer2, layer_father; // layer 指二叉树的层数,同层即同辈,后面用来比较辈分
BTREE root_replace;
BTREE create(char who[])/*use this array to create a node*/
{
BTREE n=(BTREE)malloc(sizeof(BTNode));
strcpy(n->name , who);
n->depth = 1;
n->lchild = NULL;
n->rchild = NULL;
n->par = NULL;
return n;
}
BTREE find_father(BTREE root, BTREE p1, BTREE p2) //这个函数专门用来找p1 p2结点的共同爸爸
{
BTREE temp;
while ( p1!= NULL)
{
p1 = p1->par;
temp = p2;
while (temp != NULL)
{
if (p1 == temp->par)
return p1;
temp = temp->par;
}
}
}
int main()
{
int have_child, i;
char parent[200], left[200], right[200];/*used to store the names that temp read in*/
BTREE root, p = NULL , l = NULL, r = NULL;
FILE *in;
in = fopen("in.txt", "r");
fscanf(in, "%d", &have_child); //读进来有几个人有孩子
fscanf(in, "%s %s %s", parent, left, right);
root = create(parent); //第一个读进来的parent即为根节点
p = root;
p->depth = 1;
p->par = NULL;
if( strcmp(left, "NULL") != 0 ){
l = create(left); //创建一个左孩子
l->par = p;
p->lchild = l;
l->depth = p->depth + 1;
}
else p->lchild = NULL;
if( strcmp(right,"NULL") != 0 ){
r = create(right); //创建一个右孩子
r->par = p;
p->rchild = r;
r->depth = p->depth + 1;
}
else p->rchild = NULL; //如果读入的文本中 孩子是null 的话 说明无孩子,其rchild 为空
/*building tree!*/
for(i = 0; ipar = p;
p->lchild = l;
l->depth = p->depth + 1; //他们的深度即为 父节点的深度+1
}
else p->lchild = NULL;
if( strcmp(right,"NULL") != 0 ){
r = create(right);
r->par = p;
p->rchild = r;
r->depth = p->depth + 1;
}
else p->rchild = NULL;
}
/*已经建立好二叉树 下面需要通过输入的名字找人,判断辈分*/
char name1[200], name2[200];
BTREE p1, p2, p3;
scanf("%s %s", name1, name2);
p1 = find(root, name1);
p2 = find(root, name2); //确定这两个人的树节点位置
layer1 = p1->depth; //结构当中有depth
layer2 = p2->depth;
if(layer1>layer2) /*1 is younger than 2 , print the older first*/
{
printf("%s %s %d\n", name1, name2, layer1-layer2);
}
else if(layer1depth;
printf("%s %s %d\n", p3->name, name1, layer1 - layer_father); /*now p3->name is their common father's name*/
printf("%s %s %d\n", p3->name, name2, layer2 - layer_father);
}
fclose(in);
return 0;
}