面试题7:根据前序遍历和中序遍历重建二叉树

假设输入的前序遍历和中序遍历的结果都不含重复的数字,重建二叉树并输出根节点。二叉树的定义如下:

struct BTreeNode
{
    int        value;
    BTreeNode* pLeft;
    BTreeNode* pRight;
};

解析:这道题看起来挺难,但其实可以采用递归的方法,找到规律了就很好解。前序遍历序列的第一个节点即为整个树的根,后面的序列的左半部分是左子树,而且遵循一样的规则;右半部分是右子树,也同样遵循一样的规则。中序遍历序列在中间可以找到根节点,这个节点左边的部分序列即为左子树的序列,右边部分的序列即为右子树的序列。根据中序遍历序列的左子树序列长度可以在前序遍历序列中找到左子树和右子树的分界点。找到了这个规律,写出代码就很容易了。

代码肯定采用递归的写法。首先从前序序列中读取第一个节点,即为当前树的根节点,构建这个根节点。然后在中序序列中找到这个根节点,该节点的左半部分即为左子树的中序遍历序列,该序列的长度即为左子树的节点个数。从前序序列的第二个开始,根据左子树节点个数即可推断出剩余的前序序列中多少属于左子树,剩下的属于右子树。至于边界情况,当前序序列和中序序列都只剩一个节点,那就说明构建快要完成了,如果判断前序序列的这个节点和中序序列的这个节点是同一个节点,那就说明输入的遍历序列合法。


答案:

BTreeNode* ConstructCore
    (int* startPreOrder, int* endPreOrder, int* startInOrder, int* endInOrder)
{
    //construct the root
    auto root = new BTreeNode();
    root->pLeft = root->pRight = nullptr;
    root->value = *startPreOrder;

    //there's only one node left
    if (startPreOrder == endPreOrder)
    {
        if (startInOrder==endInOrder && *startPreOrder==*startInOrder)
            return root;
        else throw exception();
    }

    //find the root in the InOrder sequence
    int *rootInOrder = startInOrder;
    while (*rootInOrder != *startPreOrder && rootInOrder<=endInOrder)
        ++rootInOrder;
    if (rootInOrder==endInOrder && *rootInOrder!=*startPreOrder)
        throw exception();

    //mark left subtree and right subtree
    int *startLeftTreePreOrder = startPreOrder+1;
    int *endLeftTreePreOrder = startPreOrder+(rootInOrder-startInOrder);
    int *startLeftTreeInOrder = startInOrder;
    int *endLeftTreeInOrder = rootInOrder-1;

    int *startRightTreePreOrder = endLeftTreePreOrder+1;
    int *endRightTreePreOrder = endPreOrder;
    int *startRightTreeInOrder = rootInOrder+1;
    int *endRightTreeInOrder = endInOrder;

    //recursively construct left subtrees and right subtrees
    if (*rootInOrder == *startPreOrder && rootInOrder>startInOrder)
        root->pLeft = 
                ConstructCore(startLeftTreePreOrder, endLeftTreePreOrder, 
                        startLeftTreeInOrder, endLeftTreeInOrder);
    if (*rootInOrder == *startPreOrder && rootInOrderpRight = 
                ConstructCore(startRightTreePreOrder, endRightTreePreOrder,
                        startRightTreeInOrder, endRightTreeInOrder);

    return root;
}

BTreeNode* 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);
}

你可能感兴趣的:(面试题7:根据前序遍历和中序遍历重建二叉树)