2016年天梯赛初赛题集 7-11 玩转二叉树 (25分)

原题

给定一棵二叉树的中序遍历和前序遍历,请你先将树做个镜面反转,再输出反转后的层序遍历的序列。所谓镜面反转,是指将所有非叶结点的左右孩子对换。这里假设键值都是互不相等的正整数。

输入格式:

输入第一行给出一个正整数N(≤30),是二叉树中结点的个数。第二行给出其中序遍历序列。第三行给出其前序遍历序列。数字间以空格分隔。

输出格式:

在一行中输出该树反转后的层序遍历的序列。数字间以1个空格分隔,行首尾不得有多余空格。

输入样例:

7
1 2 3 4 5 6 7
4 1 3 2 6 5 7

输出样例:

4 6 1 7 5 3 2


难点

难点在于DFS的逆向思维,如果做过这一类题,了解了思路,就不难做了,另外也可根据后序+中序推出二叉树,具体代码简直就是思路的翻译,所以理解思路最重要。
这里只讨论如何恢复二叉树,关于镜像翻转的思路见码知意,层序遍历也是很经典的考察点

思路

由前序遍历与中序遍历恢复二叉树的思路就是不断地找父节点在前序遍历的位置坐标
比如前序遍历中,第一个肯定是父节点,所以我们一来就能确认第一个父节点的坐标
那么如何找每个节点的坐标呢?
前序遍历是 父节点->左儿子->右儿子
所以在前序遍历中,一定是这样排列的父节点+左子树+右子树
而左子树的第一个又是父节点,所以这样层层递进下来,左边是没问题了,但是右边怎么办?
这就是中序遍历的作用了,它可以确认左子树的长度
那么父节点+1+左子树长度就是右子树的父节点了。
得到了父节点,那么操作步骤如下:

  1. 得到父节点在前序遍历的位置index,得到父节点的值(由于值是唯一的,所以可以根据值判断身份)
  2. 根据父节点的值,找到父节点在中序遍历的位置
  3. 得到左子树、右子树的长度
  4. 左儿子在前序遍历的位置index+1
  5. 右儿子在前序遍历的位置index+1+左子树长度
  6. 递归地进行,返回第一步

图演示


代码

#include
#include
using namespace std;

int n;
int* midOrder;
int* preOrder;

struct TreeNode {
    int val;
    TreeNode* lhs;
    TreeNode* rhs;
    
    TreeNode() {
        lhs = rhs = NULL;
    }
};

// 均为左闭右开区间
TreeNode* reTree(int beginInPre, int beginInMid, int endInMid) {
    if(endInMid <= beginInMid || beginInPre>n) return NULL;
    TreeNode* root = new TreeNode();
    root->val = preOrder[beginInPre];
    int rootIndexInMid = beginInMid;
    while(midOrder[rootIndexInMid]!=preOrder[beginInPre]) {
    	rootIndexInMid++;
    }
    // 左子树的长度
    int lhs_len = rootIndexInMid - beginInMid;
    root->lhs = reTree(beginInPre + 1, beginInMid, rootIndexInMid);
    root->rhs = reTree(beginInPre + 1 + lhs_len, rootIndexInMid + 1, endInMid);
    return root;
}

// 镜像翻转
void transition(TreeNode* root) {
    if(root!=NULL) {
        TreeNode* temp = root->lhs;
        root->lhs = root->rhs;
        root->rhs = temp;
        transition(root->lhs);
        transition(root->rhs);
    }
}

// 层序遍历Sequence traversal
void seqOrder(TreeNode* root) {
    bool isOutput = false;
    queue<TreeNode*> que;
    que.push(root);
    while(que.size()!=0) {
        queue<TreeNode*> que_next;
        while(que.size()!=0) {
            TreeNode* node = que.front();
            que.pop();
            if(node->lhs!=NULL) {
                que_next.push(node->lhs);
            }
            if(node->rhs!=NULL) {
                que_next.push(node->rhs);
            }
            if(isOutput) cout<<" ";
            isOutput = true;
            cout<<node->val;
        }
        if(que_next.size()==0) break;
        que = que_next;
    }
}

int main() {
    cin>>n;
    if(n==0) return 0;
    midOrder = new int[n];
    preOrder = new int[n];
    for(int i=0;i<n;++i) {
        cin>>midOrder[i];
    }
    for(int i=0;i<n;++i) {
        cin>>preOrder[i];
    }
    TreeNode* root = reTree(0, 0, n);
    transition(root);
    seqOrder(root);
    return 0;
}

你可能感兴趣的:(PAT题解,二叉树,dfs)