信息学奥赛一本通 1339:【例3-4】求后序遍历 | 洛谷 P1827 [USACO3.4] 美国血统 American Heritage

【题目链接】

ybt 1339:【例3-4】求后序遍历
洛谷 P1827 [USACO3.4] 美国血统 American Heritage
两题都是已知先序和中序遍历序列,求后序遍历序列
区别为:【ybt 1339】先输入先序遍历序列,再输入中序遍历序列。【洛谷 P1827】先输入中序遍历序列,再输入先序遍历序列。

【题目考点】

1. 二叉树

已知先序、中序边路序列,求后序遍历序列

【解题思路】

解法1:

假设输入的中序遍历序列为:DBAECH,先序遍历序列为ABDCEF。以该输入为例讨论问题解法。
当前要解决的问题是:已知先序、中序遍历序列,构建二叉树。

  1. 首先先序遍历中第一个字母为树的根结点的值(A)。
  2. 而后在中序遍历序列中找到根结点值(A)的位置,根结点值左边的序列(DB)是根结点的左子树的中序遍历序列。根结点值右边的序列(ECF)为根结点的右子树的中序遍历序列。
  3. 在先序遍历序列中根据左子树中序遍历序列的长度,找到左子树的先序遍历序列(BD),及右子树的先序遍历序列(CEF)。
  4. 递归调用“已知先序中序遍历序列求二叉树”的函数。现在已知根结点的左子树、右子树的先序、中序遍历序列,那么就可以构建出根结点的左子树与右子树(构建子树相对于构建以A为根结点的树,是小规模问题,递归求解大规模问题时,小规模问题的解被视为是已知的)
  5. 以A为根结点,接上构造好的左右子树,即完成了树的构建。

接下来对这棵树做后序遍历,即可得到树的后序遍历序列。
在这里插入图片描述

写法1:使用字符数组

输入先序遍历序列到s_pre,中序遍历序列到字符数组s_in。
函数createTree需要传入ml,mr,pl,pr,意为:由先序序列s_pre[pl]~s_pre[pr]与中序序列s_in[ml]~s_in[mr]构造一棵二叉树在这里插入图片描述
根据上述算法,先在中序序列中找到先序序列第一个字符s_pre[pl]的位置,找到位置为i。那么左子树的中序遍历序列为s_in[ml]~s_in[i-1],长度为i-ml,在先序遍历序列中,从pl+1开始取长为i-ml的序列,最后一个元素的位置为pl+i-ml,那么左子树的先序遍历序列为s_pre[pl+1]~s_pre[pl+i-ml]。类似地,可以得到右子树的中序序列为s_in[i+1]~s_in[mr],先序序列为s_pre[pl+i-ml+1]~s_pre[pr]
使用createTree分别生成左右子树,接在新分配出来的根结点的下面,就得到了这棵树。
递归出口为:先序与中序序列的下标范围一定有pl<=prml<=mr,如果不满足这一条件,序列范围无意义,应该返回。

写法2:使用string类

思路与上述方法类似,不再赘述。
使用string类,可以使用substr成员函数来取子串。每次传入函数的先序、中序序列都是string类对象。
在这里插入图片描述

【题解代码】:ybt 1339:【例3-4】求后序遍历

写法1:使用字符数组
#include <bits/stdc++.h>
using namespace std;
#define N 1005
struct Node
{
    char val;
    int left, right;
};
Node node[N];
int p;
char pre_s[105], mid_s[105];
//由先序遍历序列pre_s[pl]~pre_s[pr]与中序遍历序列mid_s[ml]~mid_s[mr]构建二叉树,返回根结点地址 
int createTree(int pl, int pr, int ml, int mr)
{
    if(pl > pr || ml > mr)
        return 0;
    int np = ++p, i;
    node[np].val = pre_s[pl];//pre_s[pl]一定是根结点的值 
    for(i = ml; i <= mr; ++i)
        if(mid_s[i] == pre_s[pl])//找到根结点在中序序列中的下标为i 
            break;
    node[np].left = createTree(pl + 1, pl + i - ml, ml, i - 1);
    node[np].right = createTree(pl + i - ml + 1, pr, i + 1, mr);
    return np;
}
void postOrder(int root)
{
    if(root == 0)
		return; 
    postOrder(node[root].left);
    postOrder(node[root].right);
    cout << node[root].val;
}
int main()
{
    cin >> pre_s >> mid_s;
    int len_pre = strlen(pre_s), len_mid = strlen(mid_s);
    int root = createTree(0, len_pre - 1, 0, len_mid - 1);
    postOrder(root);
    return 0;
}

写法2:使用string类
#include <bits/stdc++.h>
using namespace std;
#define N 1005
struct Node
{
    char val;
    int left, right;
};
Node node[N];
int p;
string s_pre, s_in;
int createTree(string sp, string si)//用先序序列sp与中序序列si构建二叉树,返回树根 
{
	int np = ++p, i;
    node[np].val = sp[0];
	for(i = 0; i < si.length(); ++i)
        if(sp[0] == si[i])
            break;
    int len_l = i, len_r = si.length() - 1 - i;//左右子树序列长度 
    if(len_l > 0)//序列长度大于0,才可以建立一棵树 
    	node[np].left = createTree(sp.substr(1, len_l), si.substr(0, len_l));
    if(len_r > 0)
		node[np].right = createTree(sp.substr(i+1, len_r), si.substr(i+1, len_r));
	return np;
}
void postOrder(int root)
{
    if(root != 0)
    {
        postOrder(node[root].left);
        postOrder(node[root].right);
        cout << node[root].val;
    }
}
int main()
{
    cin >> s_pre >> s_in;
    int root = createTree(s_pre, s_in);
    postOrder(root);
    return 0;
}

【题解代码】:洛谷 P1827 [USACO3.4] 美国血统 American Heritage

写法1:使用字符数组
#include <bits/stdc++.h>
using namespace std;
#define N 1000
struct Node
{
    char val;
    int left, right;
};
Node node[N];
int p = 1;
char s_pre[105], s_in[105];//s_pre:先序遍历序列 s_in:中序遍历序列 
//由先序序列s_pre[pl]~s_pre[pr]与中序序列s_in[ml]~s_in[mr]构造一棵二叉树,返回根结点 
int createTree(int pl, int pr, int ml, int mr)
{
    if(pl > pr || ml > mr)
        return 0;
    int np = p++, i;
    node[np].val = s_pre[pl];
    for(i = ml; i <= mr; ++i)
    {
        if(s_in[i] == s_pre[pl])
            break;
    }
    node[np].left = createTree(pl + 1, pl + i - ml, ml, i - 1);
    node[np].right = createTree(pl + i - ml + 1, pr, i + 1, mr);
    return np;
}
void postOrder(int root)
{
    if(root != 0)
    {
        postOrder(node[root].left);
        postOrder(node[root].right);
        cout << node[root].val;
    }
}
int main()
{
    cin >> s_in >> s_pre;
    int root = createTree(0, strlen(s_pre) - 1, 0, strlen(s_in) - 1);
    postOrder(root);
    return 0;
}
写法2:使用string类
#include <bits/stdc++.h>
using namespace std;
#define N 1000
struct Node
{
    char val;
    int left, right;
};
Node node[N];
int p = 1;
string s_pre, s_in;
int createTree(string sp, string si)//用先序序列sp与中序序列si构建二叉树,返回树根 
{
	int np = p++, i;
    node[np].val = sp[0];
	for(i = 0; i < si.length(); ++i)
    {
        if(sp[0] == si[i])
            break;
    }
    int len_l = i, len_r = si.length() - 1 - i;//左右子树序列长度 
    if(len_l > 0)//序列长度大于0,才可以建立一棵树 
    	node[np].left = createTree(sp.substr(1, len_l), si.substr(0, len_l));
    if(len_r > 0)
		node[np].right = createTree(sp.substr(i+1, len_r), si.substr(i+1, len_r));
	return np;
}
void postOrder(int root)
{
    if(root != 0)
    {
        postOrder(node[root].left);
        postOrder(node[root].right);
        cout << node[root].val;
    }
}
int main()
{
    cin >> s_in >> s_pre;
    int root = createTree(s_pre, s_in);
    postOrder(root);
    return 0;
}
  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
回答: 题目P1518 \[USACO2.4\] 两只塔姆沃斯牛是一道模拟题,题目要判断Farmer John和两头牛是否会相遇。解题思路可以分为两种方法。一种方法是记录二者的状态,如果出现了与前面相同的状态则说明陷入了死循环。具体实现步骤可以使用数组来记录Farmer John和两头牛的坐标、方向等状态信息,然后判断是否出现了重复的状态。另一种方法是利用博弈的思想,如果二者会同时回到一种状态,那么说明他们不会再相遇了,因为这时候他们已经陷入了一种对称性的状态。通过判断是否存在一种线性关系,可以确定二者是否会相遇。\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* [P1518 [USACO2.4]两只塔姆沃斯牛 The Tamworth Two](https://blog.csdn.net/TD123456q/article/details/125688037)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [洛谷P1518 [USACO2.4]两只塔姆沃斯牛 The Tamworth Two 题解 (C/C++)](https://blog.csdn.net/Jason__Jie/article/details/115027619)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [(移动方向状态标志)P1518 [USACO2.4]两只塔姆沃斯牛 The Tamworth Two题解](https://blog.csdn.net/m0_57221330/article/details/119980758)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值