• 信息学奥赛一本通 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 
    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;
    } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    解法2:顺序存储结构 递归先序遍历
    #include 
    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;
    } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    解法3:链式存储结构 非递归先序遍历
    #include 
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
  • 相关阅读:
    单例模式的双重检查锁定是什么
    (一)大白话MySQL执行SQL的流程
    红队打靶:Fowsniff打靶思路详解(vulnhub)
    Flink学习之flink sql
    干涉阵相关知识
    [ vulhub漏洞复现篇 ] Django debug page XSS漏洞 CVE-2017-12794
    【多模态融合】TransFusion学习笔记(2)
    RabbitMQ安装
    k8s--基础--26.3--监控告警系统--prometheus--部署
    C中volatile总结
  • 原文地址:https://blog.csdn.net/lq1990717/article/details/127680193