【剑指offer】面试题6----重建二叉树

1、题目描述

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。

例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建出如图所示的二叉树并输出他的头结点。二叉树的节点的定义如下:

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

2、解题思路

在二叉树的前序遍历中,第一个数字总是树的根节点的值。

在中序遍历序列中,根节点的值在序列的中间,左子树的结点的值位于根节点的值的左边,而右子树的结点的值位于根结点的值的右边。

因此我们需要扫描中序遍历序列,才能找到根节点的值。

这里写图片描述

【步骤】:

  • 利用递归来实现,每次依次取出前序遍历序列的节点做为根节点;
  • 遍历中序遍历序列,找到根节点所在的位置;
  • 判断下次递归的根节点是本次节点的左子树还是右子树(在中序遍历序列中,根据下次递归的节点会是本次节点的右边还是左边来决定);
  • 递归的进行创建子树;

3、源码


//二叉树节点
template<class T>
struct BinTreeNode
{
    BinTreeNode(const T& data)
        :_data(data)
        , _pLeft(NULL)
        , _pRight(NULL)
    {}
    T _data;
    BinTreeNode<T>* _pLeft;
    BinTreeNode<T>* _pRight;
};

    typedef BinTreeNode<T> Node;
    typedef Node* pNode;


    //根据前序,中序遍历结果重建二叉树
    pNode Construct(T* PreOrder, T* InOrder, T len){
        if (PreOrder == NULL || InOrder == NULL || len < 0)
            return NULL;
        return _ConstructCore(PreOrder, PreOrder + len - 1, InOrder, InOrder + len - 1);
    }


//根据前序,中序遍历结果重建二叉树
    pNode _ConstructCore(T* PreOrderStart, T* PreOrderEnd, T* InOrderStart, T* InOrderEnd){
        //先从前序遍历列表里拿到根节点,并创建根节点
        T rootValue = PreOrderStart[0];
        pNode root = new Node(rootValue);

        if (PreOrderStart == PreOrderEnd){
            if (InOrderStart == InOrderEnd && *PreOrderStart == *InOrderStart)
                return root;
            else
                throw exception("Invalid input.");
        }

        //在中序遍历中找到根节点的值
        int* rootInOrder = InOrderStart;
        while (rootInOrder <= InOrderEnd && *rootInOrder != rootValue)
            ++rootInOrder;
        //在整个中序遍历列表里都没有找到前序遍历的根
        if (rootInOrder == InOrderEnd && *rootInOrder != rootValue)
            throw exception("invalid input.");

        int leftlen = rootInOrder - InOrderStart;
        int* leftPreorderEnd = PreOrderStart + leftlen;

        if(leftlen > 0){
            //构建左子树
            root->_pLeft = _ConstructCore(PreOrderStart + 1, leftPreorderEnd, InOrderStart, rootInOrder - 1);
        }
        if (leftlen < PreOrderEnd - PreOrderStart){
            //构建右子树
            root->_pRight = _ConstructCore(leftPreorderEnd + 1, PreOrderEnd, rootInOrder + 1, InOrderEnd);
        }
        return root;
    }

4、结果

这里写图片描述

这里写图片描述

猜你喜欢

转载自blog.csdn.net/sofia_m/article/details/81276174