Advanced Experiment 4-3.1 Genealogy Processing (30 points)

Anthropological research is very interested in families, so researchers have collected genealogies of some families for research. In the experiment, a computer was used to process the family tree. To achieve this goal, the researchers converted the family tree into a text file. The following is an example of a family tree text file:

 

In the family tree text file, each line contains the name of a person. The name in the first line is the earliest ancestor of this family. The family tree contains only the descendants of the earliest ancestor, and their husbands or wives do not appear in the family tree. Everyone’s children are indented 2 spaces more than their parents. Genealogy above text file, for example, Johnthe earliest ancestors of the family, he has two children Robertand Nancy, Robertwith two children Frankand Andrew, Nancyonly a child David.

In the experiment, the researchers also collected family documents and extracted statements about the relationship between two people in the family tree. The following are examples of statements in the family tree:

 

The researcher needs to judge whether each statement is true or false. Please write a program to help the researcher judge.

Input format:

The input first gives 2 positive integers N (2≤N≤100) and M (≤100), where N is the number of names in the family tree, M is the number of statements in the family tree, and each line of input does not exceed 70 characters .

The name string consists of no more than 10 English letters. There is no indentation space before the name given in the first line of the genealogy. Other names in the family tree should be indented at least 2 spaces, that is, they are descendants of the earliest ancestor in the family tree (the name given in the first line), and if a name in the family tree is indented k spaces before the name, the name in the next line will be at most Indent k+2 spaces.

The same name will not appear twice in a genealogy, and names that do not appear in the genealogy will not appear in the statement. The format of each statement is as follows, where Xand Yare different names in the family tree:

 

Output format:

For each statement sentence in the test case, output in one line True, if the statement is true, or Falseif the statement is false.

Input sample:

 

Sample output:

 

For this question, my friends around me use multitrees and map mappings. I still like to use the binary linked list of my old friend's left child and right brother.

The type of this question is similar to the knowledge points of the directory tree that I introduced in the previous article, but I think this question as an advanced experiment is much simpler than the basic experiment of the directory tree. The idea is to use a stack to build a tree with preorder traversal, write a function to query the position of a node in the tree, and then write a Judge function to determine whether the relationship is correct. The judgment logic is also very simple. Not much to say, just show the code directly, and write detailed comments on the code, it should be easy to understand the idea. Of course, the Judge function can be optimized. Grandma Chen said that it can be optimized to two cases, but I am too lazy to optimize. It is more straightforward to divide it into five cases. But Grandma Chen also proposed a way to optimize this code, that is, to build a binary search tree for the name of the person. This query is more efficient. I will put this pit here for a while and then fill it in. If you are interested in it, You can communicate with me.

Note that we have to enter a loop to determine the relationship between the number of nodes read in and the number of nodes read in the previous one, so the first node needs special treatment because the first node does not The last node, so before entering the loop, we first build a binary tree with one node and read the earliest ancestor into this node and let preNode point to the earliest ancestor node. After that, we enter the loop again.

#include<stdio.h>
#include<stdlib.h>
#include<string>
#include<iostream>
#include<stack>
using namespace std;
int N,M;
struct TreeNode
{
	string name;
	int layer;
	TreeNode* child;
	TreeNode* sibling;
};
typedef TreeNode* PtrToTreeNode;
typedef PtrToTreeNode BinTree;
BinTree CreateNode(string name, int layer)
{
	PtrToTreeNode Node = new TreeNode;
	Node->name = name;
	Node->layer = layer;
	Node->child = NULL;
	Node->sibling = NULL;
	return Node;
}
BinTree CreateFamilyTree()
{
	int i,j,cnt,layer;//cnt用来记录空格的个数
	PtrToTreeNode Node,preNode,tmpNode;
	string s;
	stack<BinTree> sta;
	getline(cin,s);//不要用cin,cin会忽略掉单词前面的空格
	PtrToTreeNode root = CreateNode(s,0);//创建一颗只有根结点的二叉树并读入最早的祖先
	preNode = root;//令preNode指向根结点
	for(i=1; i<N; i++)//开始逐行读入人名并插入二叉树
	{
		cnt = 0;
		getline(cin,s);
		for(j=0; j<s.length(); j++)//计算空格的个数
		{
			string ss = s.substr(j,1);
			if(ss==" ")
				cnt++;
		}
		Node = CreateNode(s.substr(cnt,s.length()-cnt),cnt/2);
		if(Node->layer>preNode->layer)//如果层数大于前一个结点就插入它的左孩子
		{
			Node->sibling = preNode->child;
			preNode->child = Node;
			preNode = Node;
			sta.push(Node);//压入栈中
		}
		else if(Node->layer==preNode->layer)//层数相等说明是兄弟,插入其右兄弟的位置
		{
			Node->sibling = preNode->sibling;
			preNode->sibling = Node;
			preNode = Node;
			sta.push(Node);//压入栈中
		}
		else//层数大于前一个结点,说明这个结点应该是前一个结点的长辈,逐个弹出栈中的结点并检查
		{   //直到碰到某个结点的层数与之相同,然后插入到这个结点右兄弟位置
			while(true)
			{
				tmpNode = sta.top(); sta.pop();
				if(tmpNode->layer==Node->layer)
				{
					Node->sibling = tmpNode->sibling;
					tmpNode->sibling = Node;
					preNode = Node;
					sta.push(Node);//压入栈中
					break;
				}
			}
		}
	}
	return root;
}
PtrToTreeNode search(BinTree BT, string name)//递归的查找函数
{
	BinTree ans1,ans2;
	if(!BT) return NULL;//BT为NULL,说明查找失败,返回NULL
	if(BT->name == name)//找到了,return 地址
		return BT;
	else//未找到,分别从左孩子和右兄弟处继续递归的查找
	{
		ans1 = search(BT->child,name);
		ans2 = search(BT->sibling,name);
	}
	if(ans1) return ans1;//如果在左孩子的子树找到了就直接return地址
	else
		return ans2;//左孩子子树没找到,那就直接return右兄弟的查询结果即可
	
}
void Judge(BinTree root)//判断函数
{
	int i;BinTree x,y,ptr;
	string str[6];
	for(i=0; i<6; i++)
		cin>>str[i];
	if(str[3]=="child")
	{
		y = search(root,str[5]);//先找到父亲的位置
		if(y->child == NULL) { printf("False\n"); return; }//如果父亲没孩子,说明错误
		if(y->child->name == str[0]) { printf("True\n"); return; }//有孩子且名字也一样,说明正确
		ptr = y->child->sibling;//第一个孩子不是,那么从第一个孩子的兄弟开始找 
		while(ptr)//遍历他的所有兄弟
		{
			if(ptr->name == str[0]) { printf("True\n"); return; }
			ptr = ptr->sibling;
		}
		//都没找到,那就说明错误了
		printf("False\n"); return;
	}
	if(str[3]=="parent")//同上,把str[0]和str[5]换一下就可以了
	{
		y = search(root,str[0]);
		if(y->child == NULL) { printf("False\n"); return; }
		if(y->child->name == str[5]) { printf("True\n"); return; }
		ptr = y->child->sibling; 
		while(ptr)
		{
			if(ptr->name == str[5]) { printf("True\n"); return; }
			ptr = ptr->sibling;
		}
		printf("False\n"); return;
	}
	if(str[3]=="ancestor")
	{
		x = search(root,str[0]);//先定位祖先的位置
		y = search(x->child,str[5]);//在其孩子为根的子树中查找str[5],注意不要在以x为根的子树中去寻找,因为x的右兄弟不是x的子孙后代
		if(y)//找到了
		{
			printf("True\n"); return;
		}
		else//没找到
		{
			printf("False\n"); return;
		}
	}
	if(str[3]=="descendant")//思路同上
	{
		x = search(root,str[5]);
		y = search(x->child,str[0]);
		if(y)
		{
			printf("True\n"); return;
		}
		else
		{
			printf("False\n"); return;
		}
	}
	if(str[3]=="sibling")//判断兄弟关系
	{
		x = search(root,str[0]);//先定位兄弟str[0]
		ptr = x->sibling;
		while(ptr)//一直往右去找他的兄弟str[5],如果找到了就return true,没找到也不要紧
		{
			if(ptr->name == str[5])
			{
				printf("True\n"); return;
			}
			ptr=ptr->sibling;
		}
		x = search(root,str[5]);//定位兄弟str[5]
		ptr = x->sibling;
		while(ptr)//一直往右去找他的兄弟str[5],如果找到了就return true,没找到那就直接可以return false了
		{
			if(ptr->name == str[0])
			{
				printf("True\n"); return;
			}
			ptr=ptr->sibling;
		}
		printf("False\n"); return;
	}
}
int main()
{
	int i,j;
	string s;
	scanf("%d%d\n",&N,&M);
	BinTree root = CreateFamilyTree();//建树
	for(i=0; i<M; i++)//判断并输出
	{
		Judge(root);
	}
	return 0;
}

 

Guess you like

Origin blog.csdn.net/yiwaite/article/details/100902887