信息学奥赛一本通 1368:对称二叉树(tree_c)

【题目链接】

ybt 1368:对称二叉树(tree_c)
根据测试,可以认为输入的序列长度小于等于500

【题目考点】

1. 二叉树 顺序存储结构
  • 第1结点为树的根结点
  • 第i结点的左孩子编号为2*i,右孩子编号为2*i+1
  • 第i结点的双亲结点编号为i/2(整除运算)。
    设数组tree,tree[i]表示第i结点的值。

适合存储满二叉树与完全二叉树

【解题思路】

题目给的输入的序列是二叉树的顺序存储结构,
设数组tree,tree[i]表示用顺序存储结构保存二叉树第i结点的值。
那么输入的第i个字符就是tree[i]的值。
这里可以使用每次循环读入一个字符的方法,当读入EOF时停止读入。也可以先读入整个字符串,再做赋值。为tree数组设值。
设标志位isSym表示该树是否是对称的。
遍历整棵树(使用哪种遍历方法都可以),看每个结点的左右孩子,如果左右孩子中有1个是空结点而另一个不是,那么整棵树就不是对称的。遍历完所有结点后,可以确定该树是否是对称的。
注意在遍历顺序存储结构的树的时候,临时求出的下标可能会很大(因为每次都会乘以2),所以数组尽量开得大一些(比如最后一个结点的地址是1000,那么要把数组长度开成2000多),也可以先记录整个顺序存储结构tree数组中最后一个元素的下标tn,如果访问到的下标超过tn,那么这次访问无意义,直接返回。

本题也可以使用链式存储结构完成。题目给定的顺序存储结构字符序列,实际就是树的带空结点的层次遍历序列。可以模拟层次遍历的过程来设置结点间的关系。

在遍历时,以先序遍历为例,如果使用递归的方法做遍历,那么需要把表示该树是否对称的量声明成全局变量。如果使用非递归的方法做遍历,就可以使用函数的返回值来表示该树是否对称,效率更高。

【题解代码】

解法1:顺序存储结构 递归
#include <bits/stdc++.h>
using namespace std;
#define N 1005
char tree[N];//树的顺序存储结构,初值都为'\0',tree[i]:第i结点的值,如果为'\0'表示这里为空。
//tree[2*i]:第i结点的左孩子的值,tree[2*i+1]:第i结点右孩子的值
int tn;//tree数组最后一个元素的下标,应该保证N > 2*tn 
bool isSymmetric(int r)//判断以r为根结点的树是否是对称的 
{
	if(tree[r] == '\0')//如果遍历到空结点,那么是对称的 
		return true;
	if(tree[2*r] == '\0' && tree[2*r+1] != '\0' || 
		tree[2*r] != '\0' && tree[2*r+1] == '\0')//如果左子树空但右子树不空,或右子树空但左子树不空 
		return false;
	return isSymmetric(2*r) && isSymmetric(2*r+1);//左右子树都是对称的,该树才是对称的 
}
int main()
{
	char c;
	while((c = cin.get()) != EOF)//二叉树的顺序存储结构字符串读入tree 
	{
		if(c == '#' || c == '\n')//遇到'#'或换行符,都转为0 
			tree[++tn] = '\0';
		else
			tree[++tn] = c;
	}
	cout << (isSymmetric(1) ? "Yes" : "No");
	return 0;
} 
解法2:顺序存储结构 递归先序遍历
#include <bits/stdc++.h>
using namespace std;
#define N 105
char tree[N];//树的顺序存储结构,初值都为'\0',tree[i]:第i结点的值,如果为'\0'表示这里为空。
//tree[2*i]:第i结点的左孩子的值,tree[2*i+1]:第i结点右孩子的值
int tn;//tree数组最后一个元素的下标 
bool isSym = true;//是否对称 
void preOrder(int r)
{
	if(r > tn || tree[r] == '\0' || isSym == false)//如果超出了有效下标范围,或遍历到空结点,或已经确定是不对称的了,那么不用再遍历了 
		return;
	if(tree[2*r] == '\0' && tree[2*r+1] != '\0' || 
		tree[2*r] != '\0' && tree[2*r+1] == '\0')//如果左子树空但右子树不空,或右子树空但左子树不空 
	{
		isSym = false;//不对称
		return;
	}
	preOrder(2*r);//遍历左子树
	preOrder(2*r+1);//遍历右子树 
}
int main()
{
	char c;
	while((c = cin.get()) != EOF)//二叉树的顺序存储结构字符串读入tree 
	{
		if(c == '#' || c == '\n')//遇到'#'或换行符,都转为0 
			tree[++tn] = '\0';
		else
			tree[++tn] = c;
	}
	preOrder(1);
	cout << (isSym ? "Yes" : "No");
	return 0;
} 
解法3:链式存储结构 非递归先序遍历
#include <bits/stdc++.h>
using namespace std;
#define N 1005
struct Node
{
	char val;
	int left, right;
};
Node node[N];
int p;
string s;
int si;
int createTree()
{
	char c;
	queue<int> que;
	int np = ++p, lp, rp;
	node[np].val = s[si++];
	que.push(np);
	while(que.empty() == false)
	{
		int u = que.front();
		que.pop();
		c = s[si++];//如果已经取到末尾,c为'#',否则c取s[si] 
		if(c == '#' || si == s.length())
			lp = 0;
		else
		{
			lp = ++p;
			node[lp].val = c;
		}
		c = s[si++];
		if(c == '#' || si == s.length())
			rp = 0;
		else
		{
			rp = ++p;
			node[rp].val = c;
		}
		node[u].left = lp;
		node[u].right = rp;
		if(si < s.length())//如果没有遍历完,那么新结点入队 
		{
			que.push(lp);
			que.push(rp);
		}
	}
	return np;
}
bool isSymmetric(int r)//非递归先序遍历 判断以r为根结点的树是不是对称的 
{
	stack<int> stk;
	stk.push(r);
	while(stk.empty() == false)
	{
		int u = stk.top();
		stk.pop();
		if(node[u].left == 0 && node[u].right != 0 ||
			node[u].left != 0 && node[u].left == 0)
			return false;
		if(node[u].right != 0)
			stk.push(node[u].right);
		if(node[u].left != 0)
			stk.push(node[u].left);
	}
	return true;
}
int main()
{
	cin >> s;
	int root = createTree();
	cout << (isSymmetric(root) ? "Yes" : "No");
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值