PTA 列出叶结点 (25分)

PTA 列出叶结点
题目描述:

对于给定的二叉树,本题要求你按从上到下、从左到右的顺序输出其所有叶节点。

输入格式:

首先第一行给出一个正整数 N(≤10),为树中结点总数。树中的结点从 0 到 N−1 编号。随后 N 行,每行给出一个对应结点左右孩子的编号。如果某个孩子不存在,则在对应位置给出 “-”。编号间以 1 个空格分隔。

输出格式:

在一行中按规定顺序输出叶节点的编号。编号间以 1 个空格分隔,行首尾不得有多余空格。

输入样例:

8
1 -
- -
0 -
2 7
- -
- -
5 -
4 6

样例输出

4 1 5

这道题目呢,其实也算是一种套路,首先题目中说了从上到下,从左到右,你就应该想到,这就是层序遍历的套路呀,如果我能够找到层序遍历的数组,那么这个问题就迎刃而解了。

首先我们要明确一点,按照题目中的输入,根节点是肯定不会出现在这里面的,所以我们只需要找到没有出现的数字,然后就可以确定根节点,有了根节点,然后再模拟队列的性质,依次把他的左孩子,右孩子插入进来,然后遍历指针+1,继续插入根节点的左孩子的左孩子和右孩子…

那么问题来了,我需要用什么样的数据结构来存储这些内容呢?首先我得有一个树结点,但是这个结点呢,他不需要数据域,只需要一个左孩子和一个右孩子就可以了

struct Node
{
	int left;
	int right;
}

为什么要这么写呢?因为我一会儿会创建一个Node数组,数组的下标就是数据域,因此只需要保存每个结点的左右孩子就行了。

然后呢,我会用到一个辅助数组checked用来确定哪一个数字没有出现过,那就是根节点。

有了根节点,下一步我需要一个队列ans,首先把根节点存进去,然后从根节点开始,左孩子,右孩子,左孩子的(左孩子,右孩子),右孩子的(左孩子,右孩子)…,最后,遍历ans数组,如果有一个的 leftright 都是-1,那么说明这个就是叶结点。

#include <iostream>
#include <cstdio>
using namespace std;

struct Node
{
	int data;	
	int left;
	int right;
};
int main()
{
	int n;
	cin >> n;
	getchar();  //千万千万注意这个getchar(),否则程序会直接崩溃
	Node tree[15];   //因为这个数组的下标就是data,所以我不需要额外的data域
	int checked[15] = {};   //检查根节点的
	for(int i = 0;i < n;i++)
	{
		char l,r;	
		scanf("%c %c",&l,&r);
		getchar();  
		if(l == '-')tree[i].left = -1;
		else
		{
			tree[i].left = (l - '0');
			checked[l - '0'] = 1;
		}
		if(r == '-')tree[i].right = -1;
		else
		{
			tree[i].right = (r - '0');
			checked[r - '0'] = 1;
		}
	}
	int ans[15] = {};
	for(int i = 0;i < n;i++)
	{
		if(checked[i] == 0)
		{
			ans[0] = i;	//在这里找到了根节点,存进队列去了
			break;
		}
	}
	int k = 1;  //注意一下,k是从 1 开始的
	for(int i = 0;i < n;i++) 
	{
		if(tree[ans[i]].left != -1)ans[k++] = tree[ans[i]].left;	
		if(tree[ans[i]].right != -1)ans[k++] = tree[ans[i]].right;	
	}
	int flag = 0;
	for(int i = 0;i < n;i++)
	{
		if(tree[ans[i]].left == -1 && tree[ans[i]].right == -1)
		{
			if(flag)cout << " ";	
			flag = 1;
			cout << ans[i];
		}
	}
	return 0;
}