三叉树
题目描述
Time Limit: 1000 ms
Memory Limit: 256 mb
一个关于三叉树的题目,小于100的值代表树叶,大于100的值为分支点,
建树的过程是水平方向建树,
输入格式:
先输入n,代表有n组数据,接下来n行,输入4个数,
第一个数代表根节点,
接下来分别代表三个子节点,-1代表子节点不存在,输入的顺序按照层次遍历的次序。
接下来,要求寻找叶子节点的最短路径,最短路径是指不经过重复的边。
输入方式,首先输入一个值m,代表m行,接下来m行输入m个叶子节点和对应的优先级,要求按优先级输出从上次到达的位置到该节点的最短路径,每条路径的最后一个节点要求输出目标叶子节点,最后要求回到根节点。
输入样例#
10
100 101 108 107
101 1 102 2
108 103 104 105
107 17 109 18
102 3 4 5
103 7 8 9
104 10 106 11
105 15 16 -1
109 19 20 21
106 12 13 14
5
8 1
14 3
16 2
5 0
19 4
输出样例#:
100 101 102 5
102 101 100 108 103 8
103 108 105 16
105 108 104 106 14
106 104 108 100 107 109 19
109 107 100
- 关键点:
*** 使用sort函数对数据预处理
*** 根据给定的条件建树
*** 根据给定的值,寻找在树中的位置
*** 寻找公共祖先节点(带有父指针)
1.方案一、寻找第一个相交的点(层数高的先走几步,直至层数相同,然后判断每走一步是否有公共的祖先节点)
2.方案二、利用后序遍历求解公共祖先节点
*** 先序遍历输出路径
#include<stdio.h>
#include<stdlib.h>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
int input[100][4];
struct prior
{
int id;
int pri;
}ssd[100];
int n,m;
bool cmp(prior a,prior b)
{
if(a.pri < b.pri) return true;
else return false;
}
typedef struct node
{
int id;
int layer;//用于寻找公共祖先节点
node* parent;
node* lchild;
node* mchild;
node* rchild;
}Node,*Tree;
Node* newNode(int id)
{
Node* temp = (Node*)malloc(sizeof(Node));
temp->id = id;
temp->layer = 0;
temp->parent = temp->lchild = temp->mchild = temp->rchild = NULL;
return temp;
}
/*
递归建树:
初始状态 层数和父节点已经建立
*/
void createTree(Node* root)
{
int i;
for(i = 0;i<n;i++)
{
if(root->id == input[i][0])
break;
}
if(i == n)
return ;
if(input[i][1]!=-1)
{
Node* temp1 = newNode(input[i][1]);
temp1->layer = root->layer + 1;
root->lchild = temp1;
temp1->parent = root;
createTree(temp1);
}
if(input[i][2] != -1)
{
Node* temp2 = newNode(input[i][2]);
temp2->layer = root->layer + 1;
temp2->parent = root;
root->mchild = temp2;
createTree(temp2);
}
if(input[i][3]!=-1)
{
Node* temp3 = newNode(input[i][3]);
temp3->layer = root->layer + 1;
temp3->parent = root;
root->rchild = temp3;
createTree(temp3);
}
}
void preOrder(Node* root)
{
if(root)
{
if(root->id == input[0][0])
printf("%d %d\n",root->id,root->layer);
else
printf("%d %d %d\n",root->id,root->layer,root->parent->id);
preOrder(root->lchild);
preOrder(root->mchild);
preOrder(root->rchild);
}
}
void layerOrder(Node* root)
{
queue<Node*> q;
q.push(root);
while(!q.empty())
{
Node* qhead = q.front();
if(qhead->id == input[0][0])
printf("%d %d\n",qhead->id,qhead->layer);
else
printf("%d %d %d\n",qhead->id,qhead->layer,qhead->parent->id);
if(qhead->lchild)
q.push(qhead->lchild);
if(qhead->mchild)
q.push(qhead->mchild);
if(qhead->rchild)
q.push(qhead->rchild);
q.pop();
}
}
vector<Node*> tempPath,ansPath;
/*
实际问题:给定的孩子节点,肯定能够找到
*/
//******
Node* findChildPosition(Node* root,int childId)//有返回值的情况下只需要找到一条路径即可返回,一般情况下题目中只有一条路径
{
if(root == NULL)
return NULL;
if(root->id == childId)
return root;//找到了,或者到达终点没找到
/*
Node* temp = findChildPosition(root->lchild,childId);
if(temp!= NULL)//通过左子树找到
return temp;
else
temp = findChildPosition(root->mchild,childId);
if(temp != NULL)//通过中子树找到
return temp;
else
temp = findChildPosition(root->rchild,childId);
if(temp!=NULL)//通过右子树找到
return temp;
else//通过所有的子树均找不到
return NULL;
*/
Node *tmp1,*tmp2,*tmp3;
tmp1 = findChildPosition(root->lchild,childId);
if(tmp1)
return tmp1;
tmp2 = findChildPosition(root->mchild,childId);
if(tmp2)
return tmp2;
tmp3 = findChildPosition(root->rchild,childId);
if(tmp3)
return tmp3;
return NULL;//通过左子树,中子树,右子树均为找到孩子节点
/*
下面的这种写法值得自己仔细的思考
以前的认识是错误的,哈哈哈哈非常的开心啊
思考:下面的这种方法就本题而言,打印路径是绝对没有问题的,但是在返回ChildId的位置的时候发生错误
tempPath.push_back()和tempPath.pop_back()的位置,是输出多有能够到达指定终点的路径
就本题而言,只有一条路径所以只会打印一条;
但是作为返回值:下面这种写法是错误的,因为在某一条子节点找到之后并不会这个节点的位置
而是继续寻找,这样的话就丢失了这个位置。返回值就是错误的。
*/
/*
Node* temp = NULL;
if(root->id == childId)
{
tempPath.push_back(root);
for(int i = 0;i<tempPath.size();i++)
{
if(i == tempPath.size()-1)
printf("%d\n",tempPath[i]->id);
else
printf("%d ",tempPath[i]->id);
}
tempPath.pop_back();
return root;
}
if(root->lchild == NULL && root->mchild == NULL && root->rchild == NULL)
return NULL;
tempPath.push_back(root);//首先将当前节点加入tempPath
if(root->lchild)//访问其相邻的子节点
{
temp = findAndPrintChild(root->lchild,childId);
}
if(root->mchild)
{
temp = findAndPrintChild(root->mchild,childId);
}
if(root->rchild)
{
temp = findAndPrintChild(root->rchild,childId);
}
tempPath.pop_back();//到达这一步说明通过root的子节点到达不了目的节点,将root节点删除
return temp;
*/
}
Node* findSameAncient(Node *root,int id1,int id2)
{
Node *temp1,*temp2;
int layer1,layer2;
temp1 = findChildPosition(root,id1);
temp2 = findChildPosition(root,id2);
layer1 = temp1->layer;
layer2 = temp2->layer;
if(layer1 > layer2)
{
int c = layer1 - layer2;
while(c--)
{
temp1 = temp1->parent;
}
}
if(layer1<layer2)
{
int d = layer2 - layer1;
while(d--)
{
temp2 = temp2->parent;
}
}
if(temp1 == temp2) return temp1;
while(temp1->parent->id != temp2->parent->id)
{
temp1 = temp1->parent;
temp2 = temp2->parent;
}
return temp1->parent;
}
Node* prePrint(Node* root,int id)//树中只存在一条路径,不需要寻找所有的路径
{
if(root == NULL) return NULL;
if(root->id == id)
{
tempPath.push_back(root);
for(int i = 0;i<tempPath.size();i++)
{
if(i == tempPath.size()-1)
printf("%d\n",tempPath[i]->id);
else
printf("%d ",tempPath[i]->id);
}
tempPath.pop_back();
return root;
}
tempPath.push_back(root);
Node* tempNode = prePrint(root->lchild,id);
tempPath.pop_back();
if(tempNode)
return tempNode;
tempPath.push_back(root);
tempNode = prePrint(root->mchild,id);
tempPath.pop_back();
if(tempNode)
return tempNode;
tempPath.push_back(root);
tempNode = prePrint(root->rchild,id);
tempPath.pop_back();
if(tempNode)
return tempNode;
return NULL;//表示通过三个子节点之后没有找到,返回NULL
}
void print_out(Node* root)
{
prePrint(root,ssd[0].id);
Node *child1,*sameParent,*child2;
for(int i = 0;i<m-1;i++)
{
child1 = findChildPosition(root,ssd[i].id);
child2 = findChildPosition(root,ssd[i+1].id);
sameParent = findSameAncient(root,ssd[i].id,ssd[i+1].id);
while(child1->parent!=sameParent)
{
printf("%d ",child1->parent->id);
child1 = child1->parent;
}
prePrint(sameParent,ssd[i+1].id);
}
child1 = findChildPosition(root,ssd[m-1].id);
while(child1->parent!=sameParent)
{
printf("%d ",child1->parent->id);
child1 = child1->parent;
}
printf("%d\n",root->id);
}
int main()
{
/*
数据输入
*/
int i;
scanf("%d",&n);
for(i = 0;i<n;i++)
{
scanf("%d%d%d%d",&input[i][0],&input[i][1],&input[i][2],&input[i][3]);
}
scanf("%d",&m);
for(i = 0;i<m;i++)
{
scanf("%d%d",&ssd[i].id,&ssd[i].pri);
}
/*
初始化变量
*/
/*
数据处理
*/
//建树
Node* root = newNode(input[0][0]);
root->layer = 1;
root->parent = NULL;
createTree(root);
sort(ssd,ssd + m,cmp);
print_out(root);
return 0;
}
/*
IN:
10
100 101 108 107
101 1 102 2
108 103 104 105
107 17 109 18
102 3 4 5
103 7 8 9
104 10 106 11
105 15 16 -1
109 19 20 21
106 12 13 14
5
8 1
14 3
16 2
5 0
19 4
OUT:
100 101 102 5
102 101 100 108 103 8
103 108 105 16
105 108 104 106 14
106 104 108 100 107 109 19
109 107 100
*/