#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);
}
//2018/3/13
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<ctype.h>
#define NAME 20
//建立一棵二叉树
struct node
{//每个树节点包括
char name[NAME]; //自己节点的名字
node* lc; //左孩子指针
node* rc; //右孩子指针
char pname[NAME]; //父节点名字
int generation; //自己的树深
};
bool IsWord(char a)//判断是不是字符
{
if(a>'a'&&a<'z'||a>'A'&&a<'Z'||a=='_')
return true;
return false;
}
void GetName(char str[100],int index,char* parent,char* lchild,char* rchild)//切分字符串中的名字
{
int i=0,j=0;
while(IsWord(str[i]))
{
parent[j++]=str[i++];
}
parent[j]='\0';
while(!IsWord(str[i]))
i++;
j=0;
while(IsWord(str[i]))
{
lchild[j++]=str[i++];
}
lchild[j]='\0';
while(!IsWord(str[i])&&i<index)
i++;
j=0;
while(IsWord(str[i])&&i<index)
{
rchild[j++]=str[i++];
}
rchild[j]='\0';
while(!IsWord(str[i])&&i<index)
i++;
}
bool IsSame(char *a,char *b)//判断名字是否相同
{
int len1=strlen(a);
int len2=strlen(b);
if(len1!=len2)
return false;
int i;
for(i=0;i<len1;i++)
{
if(a[i]!=b[i])
return false;
}
return true;
}
node* FindNode(node* root,char* parent) //先序遍历 查找name为parent的树节点
{
if(root==NULL)
return NULL;
if(IsSame(root->name,parent)) //先序遍历根节点
return root;
else
{
node* result = FindNode(root->lc,parent);//先序遍历左孩子
if(result==NULL)
result=FindNode(root->rc,parent);//先序遍历右孩子
return result;
}
}
node* AddNode(node* root,char* parent,char* lchild,char* rchild)//添加节点
{
if(root == NULL)//若没有根节点 则首先为根节点分配空间并建立根节点
{
root = (node*)malloc(sizeof(node));
strcpy(root->name,parent);
root->lc=NULL;//暂时初始化左右孩子为NULL
root->rc=NULL;
strcpy(root->pname,'\0');
root->generation=0;
}
node* temp=FindNode(root,parent);//在根节点为root的整棵树中,找到名字为parent的节点 并用指针temp指向该节点
printf("%s\n",temp->name);
node* lc=(node*)malloc(sizeof(node));//建立左孩子
strcpy(lc->name,lchild);
strcpy(lc->pname,parent);
lc->generation = temp->generation+1;
lc->lc=NULL;
lc->rc=NULL;
node* rc=(node*)malloc(sizeof(node));//建立右孩子
strcpy(rc->name,rchild);
strcpy(rc->pname,parent);
rc->generation=temp->generation+1;
rc->lc=NULL;
rc->rc=NULL;
temp->lc=lc;//连接左孩子
temp->rc=rc;//连接右孩子
return root;//返回根节点 相当于返回整棵树
}
void FindRelation(node* root,char* person1,char* person2)
{
node*p1=FindNode(root,person1);//查找name为person1的节点
node*p2=FindNode(root,person2);//查找name为person2的节点
node* min;
node* max;
if(p1->generation>p2->generation)
{
min=p1;max=p2;
}
else
{
min=p2;max=p1;
}
int level=min->generation-max->generation;
while(min->generation>max->generation)//找到同一辈分 就是将小辈分雨大辈分处于同一辈分上寻找共同祖先
{
char* parent=min->pname;
min=FindNode(root,parent);
}
while(!IsSame(min->pname,max->pname))//如果此时不是共同祖先 就向上推一层再找共同祖先 直到找到共同祖先
{
char* parent=min->pname;
min=FindNode(root,parent);
parent=max->pname;
max=FindNode(root,parent);
}
printf("%s %d\n",min->pname,level);
}
int main()
{
node* root = NULL;//建立一个根节点指针
char ch;
int tag=0;//用于控制输入与输出
char parent[NAME],lchild[NAME],rchild[NAME];//建立三个字符串分别用于输入父名 左子名 右子名
while(tag=0 && (ch=getchar())!=EOF)
{
parent[0]=lchild[0]=rchild[0]='\0';//每次输入都初始化
char str[3*NAME+2];
int index=0;//index个字符
ch=getchar();
while(ch!='\n')//直到输入换行
{
str[index++]=ch;
ch=getchar();
}
str[index]='\0';
// printf("%s\n",str);
GetName(str,index,parent,lchild,rchild);//切分字符串
printf("%s\t%s\t%s\n",parent,lchild,rchild);
if(strlen(rchild))//0找关系 1添加
{
root = AddNode(root,parent,lchild,rchild);//输入三项 就添加节点 root相当于整颗树 它指向整棵树的根节点
}
else if(strlen(rchild)==0)//只输入2项 则找关系
{
FindRelation(root,parent,lchild);
tag=1;
}
}
return 0;
}