剑指offer之面试题7:重建二叉树

重建二叉树

1、题目

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

输入参数:前序遍历序列、中序遍历序列、序列的长度

输出结果:二叉树的根节点指针,或者为空

2、解题

首先,一个二叉树节点的定义如下,包括数据域和两个指向孩子节点的指针

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

其次,分析前序遍历序列和中序遍历序列。

前序遍历序列的排列为:根节点 —— 左子树 —— 右子树

中序遍历序列的排列为:左子树 —— 根节点 —— 右子树

所以,解题的核心步骤为:

  • 在前序遍历序列找到根节点
  • 在中序遍历序列找到根节点的位置
  • 通过递归调用构建左右子树
  • 返回根节点
3、鲁棒性

本题目的关键在于提高代码的鲁棒性。

鲁棒性(Robust)的定义指程序能够判断输入是否合乎规范要求,并对不符合规范的输入进行合理的处理

提高代码鲁棒性的方法:防御性编程

防御性编程的定义指遇见在什么地方出现问题,并为这些可能的问题制定处理方式

本题需要考虑三个地方

  • 传入的前序、中序遍历序列、长度这三个参数的正确性
  • 二叉树只有一个节点,输入序列的正确性
  • 在中序遍历序列中无法找到根节点的情况
4、完整代码
BinaryTreeNode* construct(int* preorder, int* inorder, int length){
    //第一次鲁棒性判断
    if(preorder == null || inorder == null || length <= 0)
        return null;
    
    return constructCore(preorder, preorder+length-1, inorder, inorder+length-1);
}

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("Invalid input.");
    }
    //开始编写核心代码
    int* rootInorder = startInorder;
    while (rootInorder <= endInorder && *rootInorder != rootValue)
        rootInorder++;
    //第三次鲁棒性判断
    if (rootInorder > endInorder)
        throw std::exception("Invalid input.");

    int leftLength = rootInorder - startInorder;
    int* leftPreorderEnd = startPreorder + leftLength;
    //开始构建左子树和右子树
    if (leftLength > 0) {
        root->m_pLeft =  constructCore(startPreorder + 1, leftPreorderEnd, 						startInorder, rootInorder - 1);
    }
    if (leftLength < endPreorder - startPreorder) {
        root->m_pRight = constructCore(leftPreorderEnd + 1, endPreorder, rootInorder + 				1, endInorder);
    }
    //最后返回根节点
    return root;
}
5、注意点
  • 构建左右子树的时候需要记得将其赋值给根节点的两个孩子指针
  • 创造二叉树的根节点时,需将其初始化
  • 最后记得返回根节点
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值