输入某二叉树的前序遍历和中序遍历的结果,重建出该二叉树

//==================================================================
// 《剑指Offer——名企面试官精讲典型编程题》代码
// 作者:何海涛
//==================================================================

// 面试题7:重建二叉树
// 题目:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输
// 入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,
// 2, 4, 7, 3, 5, 6, 8}和中序遍历序列{4, 7, 2, 1, 5, 3, 8, 6},则重建出
// 图中所示的二叉树并输出它的头结点。
#include <iostream>
#include <cstdio>
#include "..\Utilities\BinaryTree.h"
using namespace std;

struct BinaryTreeNode
{
    int                    m_nValue;
    BinaryTreeNode*        m_pLeft;
    BinaryTreeNode*        m_pRight;
};

BinaryTreeNode* ConstructCore(int* startPreorder, int* endPreorder,
                                int* startInorder, int* endInorder) {
    // 前序遍历的第一个数字是根结点的值
    // 获得根结点并初始化
    int rootValue = startPreorder[0];
    BinaryTreeNode* root = new BinaryTreeNode();
    root->m_nValue = rootValue;
    root->m_pLeft = root->m_pRight = nullptr;

    // 当前序遍历和中序遍历的两个数组的两端的指针都指向同一个元素,
    // 并且这个元素的值还相等时,表示递归结束
    if (startPreorder == endPreorder) {
        if (startInorder == endInorder && *startPreorder == *startInorder){
            return root;
        } else {
            throw std::exception();
        }
    }

    // 在中序遍历中定位到根节点,直到*rootInorder == rootValue
    int* rootInorder = startInorder; // 从划分出的头开始
    while(rootInorder <= endInorder && *rootInorder != rootValue) {
        ++rootInorder; // 不是就指针+1,向后移动继续查找
    }

    if (rootInorder == endInorder && *rootInorder != rootValue) {
        throw std::exception();
    }

    // 利用指针的减法算出相对于当前根结点的左子树的数量
    int leftLength = rootInorder - startInorder;
    // 得到在前序遍历中指向最后一个左子树的元素的指针
    int* leftPreorderEnd = startPreorder + leftLength;
    if (leftLength > 0) {
        // 构建左子树,前序遍历数组头部指针往右移,中序遍历数组根节点指针往左移,两个数组均排除一个定位好的节点
        root->m_pLeft = ConstructCore(startPreorder + 1, leftPreorderEnd, startInorder, rootInorder - 1);
    }
    // endPreorder - startPreorder的值就是下一层元素的总个数,
    // 当leftLength = endPreorder - startPreorder时,就表明下一层只有左子树
    // 当他小于这个值时,就说明下一层有右子树
    // 当然,他不可能大于这个值,因为他是中序遍历中 根结点左边元素的个数
    if (leftLength < endPreorder - startPreorder) {
        // 构建右子树,前序遍历数组尾部指针往左移,中序遍历数组根结点指针往右移,两个数组均排除一个定位好的节点
        root->m_pRight = ConstructCore(leftPreorderEnd + 1, endPreorder, rootInorder + 1, endInorder);
    }
    return root;

}

BinaryTreeNode* Construct(int *preorder, int* inorder, int length) {
    if (preorder == nullptr || inorder == nullptr || length <= 0) {
        return nullptr;
    }

    return ConstructCore(preorder, preorder + length -1,
                            inorder, inorder + length -1);
}

部分分析过程:

由此可以总结出:

二叉树的前序遍历中,第一个数字总是树的根结点的值
二叉树的中序遍历中,根结点的值在序列的中间,左子树的值位于根结点的左边,右子树的值位于根结点的右边
根据这两个特点,这道题的解法就是从根结点出发递归的划分左右子树
1. 根据前序遍历找到根结点
2. 根据根结点的值,在中序遍历中定位到根结点
3. 根据中序遍历中定位到的根结点,计算出左子树的长度
4. 根据左子树的长度判断是否能构建左右子树
5. 构建子树时,根据划分出的左右子树范围,移动指针,两组指针始终位于要构建的左右子树的两端,然后递归
6. 根据4个指针是否都指向同一个值作为递归的终止条件

原文地址:https://www.cnblogs.com/Lothlorien/p/10330415.html

时间: 2024-08-26 15:00:05

输入某二叉树的前序遍历和中序遍历的结果,重建出该二叉树的相关文章

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

问题描述: 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回. 思路: 在二叉树的前序遍历序列中,第一个数字总是树的根结点的值.但在中序遍历序列中,根结点的值在序列的中间,左子树的结点的值位于根结点的值的左边,而右子树的结点的值位于根结点的值的右边.因此我们需要扫描中序遍历序列,才能找到根结点的值. 如下图所示,

题目:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树

问题描述: 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回. 思路: 在二叉树的前序遍历序列中,第一个数字总是树的根结点的值.但在中序遍历序列中,根结点的值在序列的中间,左子树的结点的值位于根结点的值的左边,而右子树的结点的值位于根结点的值的右边.因此我们需要扫描中序遍历序列,才能找到根结点的值. 如下图所示,

根据二叉树的前序遍历和中序遍历重建二叉树

题目描述 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回. 1 /** 2 * Definition for binary tree 3 * struct TreeNode { 4 * int val; 5 * TreeNode *left; 6 * TreeNode *right; 7 * TreeNode(

027依据前序遍历和中序遍历,重建二叉树(keep it up)

剑指offer中题目:http://ac.jobdu.com/problem.php?pid=1385 题目描写叙述: 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.如果输入的前序遍历和中序遍历的结果中都不含反复的数字. 比如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并输出它的后序遍历序列. 输入: 输入可能包括多个測试例子,对于每一个測试案例, 输入的第一行为一个整数n(1<=n<=1000):代表二叉树的节点

二叉树、前序遍历、中序遍历、后序遍历

一.树 在谈二叉树前先谈下树和图的概念 树:不包含回路的连通无向图(树是一种简单的非线性结构) 树有着不包含回路这个特点,所以树就被赋予了很多特性 1.一棵树中任意两个结点有且仅有唯一的一条路径连通 2.一棵树如果有n个结点,那它一定恰好有n-1条边 3.在一棵树中加一条边将会构成一个回路 4.树中有且仅有一个没有前驱的结点称为根结点 在对树进行讨论的时候将树中的每个点称为结点, 根结点:没有父结点的结点 叶结点:没有子结点的结点 内部结点:一个结点既不是根结点也不是叶结点 每个结点还有深度,比

N4-某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。

题目描述 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回. //本题思路参考另一个大神写的代码 其原地址为:https://www.nowcoder.com/profile/566744/codeBookDetail?submissionId=1516321 /** * 输入某二叉树的前序遍历和中序遍历的结果,

已知二叉树的前序遍历、中序遍历或者中序遍历、后序遍历求二叉树结构的算法

二叉树中的前序遍历是先访问根结点,再访问左子树,右子树. 中序遍历是先访问左子树,再是根结点,最后是右子树. 后序遍历是先访问左子树,再是右子树,最后是根结点. 算法思路是先根据前序遍历的第一个结点或者后序遍历的最后一个结点,查找对应在中序遍历中的位置,就可以确定左子树包含的元素和右子树包含的元素,最后通过递归来实现就可以了. 二叉树的表示形式为 //二叉树的结构表示为 class TreeNode { int val; TreeNode left; TreeNode right; TreeNo

前序遍历和中序遍历重建二叉树

对于二叉树,在此我不做过多讲解,如有不懂,请参照一下链接点击打开链接 1.在此二叉树的定义: struct BinaryTreeNode     {         BinaryTreeNode<T> *_Left;         BinaryTreeNode<T> *_Right;         T _data;     public:         BinaryTreeNode(const T& x)             :_Left(NULL)       

二叉树(14)----由前序遍历和中序遍历重建二叉树

1.二叉树定义 typedef struct BTreeNodeElement_t_ { void *data; } BTreeNodeElement_t; typedef struct BTreeNode_t_ { BTreeNodeElement_t *m_pElemt; struct BTreeNode_t_ *m_pLeft; struct BTreeNode_t_ *m_pRight; } BTreeNode_t; 二.根据前序遍历序列和中序遍历序列重建二叉树 算法说明: 由中序遍历序