PAT甲级1119 Pre- and Post-order Traversals

PAT甲级1119 Pre- and Post-order Traversals

Suppose that all the keys in a binary tree are distinct positive integers. A unique binary tree can be determined by a given pair of postorder and inorder traversal sequences, or preorder and inorder traversal sequences. However, if only the postorder and preorder traversal sequences are given, the corresponding tree may no longer be unique.

Now given a pair of postorder and preorder traversal sequences, you are supposed to output the corresponding inorder traversal sequence of the tree. If the tree is not unique, simply output any one of them.

Input Specification:
Each input file contains one test case. For each case, the first line gives a positive integer N (30), the total number of nodes in the binary tree. The second line gives the preorder sequence and the third line gives the postorder sequence. All the numbers in a line are separated by a space.

Output Specification:
For each test case, first printf in a line Yes if the tree is unique, or No if not. Then print in the next line the inorder traversal sequence of the corresponding binary tree. If the solution is not unique, any answer would do. It is guaranteed that at least one solution exists. All the numbers in a line must be separated by exactly one space, and there must be no extra space at the end of the line.

Sample Input 1:
7
1 2 3 4 6 7 5
2 6 7 4 5 3 1
结尾无空行
Sample Output 1:
Yes
2 1 6 4 7 3 5
结尾无空行
Sample Input 2:
4
1 2 3 4
2 4 3 1
结尾无空行
Sample Output 2:
No
2 1 3 4
结尾无空行

先序遍历和后序遍历确定中序遍历,构建的二叉树不一定是唯一的,可以看看下面的链接
https://blog.csdn.net/waple_0820/article/details/81837875

总结就是假设一个父节点,如果它只有一个子节点的情况,没有办法确定子节点是左节点还是右节点(因为先序遍历是根左右,后序是左右根)

举个例子,先序为1 2 3 4,后序为2 4 3 1,构建的二叉树有下面两种情况:
在这里插入图片描述
构建的流程是:每一步需要区分根节点和其左右子树,用上面例子来说明:
1、先序遍历第一个数就是二叉树的根节点1

2、现在寻找根节点1的左右子树,即找到先序和后序中左右子树的范围(左子树的节点肯定是比右子树的节点出现早的,假设在先序中从第1个元素到第i个元素是左子树,那么从第i + 1个元素到n - 1元素是右子树;对应在后序中从第0元素到第j元素是左子树,那么从第j + 1元素到n - 2元素是右子树),在这一题里先序中根节点下一个元素是2,所以2就是左子树根节点,寻找后序中2所在位置,发现2前面没有元素,即根节点为1,左子树中只有2一个元素(这是因为后序是左右根,如果左子树中除了2还有其它元素,那么他肯定会出现在后序中2以前),右子树即为4 3

3、根据上一步我们确定了1为根节点,左子树为2,右子树为4 3,因此对左子树和右子树根据上一步的流程继续操作。左子树的先序为2,后序为2,右子树先序为3 4,后序为4 3(这里可以看到右子树的树根为3,还剩下一个4无法确定是3的左节点还是右节点,因此这种情况就属于无法得到唯一的二叉树)

下面是题目中的例子:
在这里插入图片描述
递归规则:
*1、根节点是当前先序的首个元素,后序的末尾元素
2、先序的首个元素的下一个元素是左子树根节点,后序中该元素对应位置到后序的首个元素的范围内,都是左子树节点;后序的该位置的后一元素到末尾元素的前一个元素为止的范围内都是右子树节点。
(1)如果左子树或右子树出现偶数个节点的情况,那么树不唯一;否则唯一
(2)如果左子树或右子树的起点大于终点,那么意味着该根节点不存在左子树或右子树
(3)如果左子树或右子树的起点等于终点,那么意味着该左子树或右子树是叶子节点
**

下面是我的代码:

#include <iostream>
#include <vector>
using namespace std;
struct node {
    int data;
    node* lchild;
    node* rchild;
}tree[50];
vector<int> pre;
vector<int> post;
int n;
int loc = 0;
node* creat() {
    tree[loc].lchild = tree[loc].rchild = nullptr;
    return &tree[loc++];
}

bool flag = true;
node* build(int s1, int e1, int s2, int e2) {
    if (s1 > e1 || s2 > e2) {
        return nullptr;
    }
    node* root = creat();
    root->data = pre[s1];
    if (s1== e1) {
        return root;
    }
    else {
        int temp = pre[s1 + 1];
        int left_root;
        for (int i = s2; i <= e2; ++i) {
            if (temp == post[i]) {
                left_root = i;
                break;
            }
        }
        if ((left_root - s2 + 1) % 2 == 0 || (e2 - 1 - left_root) % 2 == 0) {
            flag = false;
        }
        root->lchild = build(s1 + 1, s1 + left_root - s2 + 1, s2, left_root);
        root->rchild = build(s1 + left_root - s2 + 2, e1, left_root + 1, e2 - 1);
        return root;
    }
}
bool out_flag = false;
void inorder(node* root) {
    if (root->lchild != nullptr) {
        inorder(root->lchild);
    }
    if (out_flag == false) {
        cout << root->data;
        out_flag = true;
    }
    else {
        cout << ' ' << root->data;
    }
    if (root->rchild != nullptr) {
        inorder(root->rchild);
    }
}
int main() {
    cin >> n;
    pre.resize(n);
    post.resize(n);
    for (int i = 0; i < n; ++i) {
        cin >> pre[i];
    }
    for (int i = 0; i < n; ++i) {
        cin >> post[i];
    }
    node* root = build(0, n - 1, 0, n - 1);
    if (flag == true) {
        cout << "Yes" << endl;
    }
    else {
        cout << "No" << endl;
    }
    inorder(root);
    cout << endl;
    return 0;
}

以下代码是不需要构建二叉树,而是在遍历先序和后序的过程中中序遍历:

这个过程其实和上面构建二叉树的过程是一样的,只是少了构建树的步骤,注意除了中序遍历的模板在递归中间将元素加入数组的操作以外,还要在s1 == e1时将元素加入数组,因为这个时候元素是叶子节点,按照代码的流程它需要特别加入

#include <iostream>
#include <vector>
using namespace std;
vector<int> pre;
vector<int> post;
vector<int> in;
int n;
bool unique = true;

void getin(int s1,int e1,int s2,int e2){
    if(s1 > e1||s2 > e2){
        return;
    }
    if(s1 == e1){
        in.push_back(pre[s1]);
        return;
    }
    int left_root = pre[s1 + 1];
    int rootidx;
    for(int i = s2;i <= e2;++i){
        if(post[i] == pre[s1 + 1]){
            rootidx = i;
            break;
        }
    }
    if((rootidx - s2 + 1) % 2 == 0||(e2 - rootidx - 1) % 2 == 0){
        unique = false;
    }
    getin(s1 + 1,rootidx - s2 + s1 + 1,s2,rootidx);
    in.push_back(pre[s1]);
    getin(rootidx - s2 + s1 + 2,e1,rootidx + 1,e2 - 1);
    return;
}

int main(){
    cin >> n;
    pre.resize(n);
    post.resize(n);
    for(int i = 0;i < n;++i){
        cin >> pre[i];
    }
    for(int i = 0;i < n;++i){
        cin >> post[i];
    }
    getin(0,n - 1,0,n - 1);
    if(unique == false){
        cout << "No" << endl;
    }
    else{
        cout << "Yes" << endl;
    }
    for(int i = 0;i < n;++i){
        if(i != 0){
            cout << ' ';
        }
        cout << in[i];
    }
    cout << endl;
    return 0;
}

这题还要注意的是如果测试点出现格式错误,可以看看是不是输出最后没有换行、中序遍历最后一个元素后面多了一个空格

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值