剑指offer--重建二叉树

17 篇文章 0 订阅

记录来自《剑指offer》上的算法题目。
题目如下:

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

二叉树的结点定义如下:

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 = NULL;

    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 && *rootInorder != rootValue)
        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;
}
// 重建二叉树,根据输入的前序序列和中序序列
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);
}

测试代码如下:

// 前序遍历输出
void PreOutput(BinaryTreeNode* root){
    if (root == NULL)
        return;
    cout << root->m_nValue << " ";
    PreOutput(root->m_pLeft);
    PreOutput(root->m_pRight);
}
// 中序遍历输出
void InOutput(BinaryTreeNode* root){
    if (root == NULL)
        return;
    InOutput(root->m_pLeft);
    cout << root->m_nValue << " ";
    InOutput(root->m_pRight);
}

// 测试
int main(void){
    // 不完全二叉树
    int pre1[] = {1,2,4,7,3,5,6,8};
    int in1[] = {4,7,2,1,5,3,8,6};
    BinaryTreeNode* root = Construct(pre1, in1, 8);
    cout << "不完全二叉树前序遍历输出:";
    PreOutput(root);
    cout << endl;
    cout << "中序遍历输出:";
    InOutput(root);
    cout << endl;
    // 完全二叉树
    int pre2[] = { 1, 2, 4, 8, 9, 5, 3, 6, 7 };
    int in2[] = { 8, 4, 9, 2, 5, 1, 6, 3, 7 };
    root = Construct(pre2, in2, 9);
    cout << "\n完全二叉树前序遍历输出:";
    PreOutput(root);
    cout << endl;
    cout << "中序遍历输出:";
    InOutput(root);
    cout << endl;
    // 所有结点都没有右子结点的二叉树,即左斜树
    int pre3[] = { 1, 2, 3, 4, 5 };
    int in3[] = { 5, 4, 3, 2, 1 };
    root = Construct(pre3, in3, 5);
    cout << "\n左斜树前序遍历输出:";
    PreOutput(root);
    cout << endl;
    cout << "中序遍历输出:";
    InOutput(root);
    cout << endl;
    // 右斜树
    int pre4[] = { 1, 2, 3, 4, 5 };
    int in4[] = { 1, 2, 3, 4, 5 };
    root = Construct(pre4, in4, 5);
    cout << "\n右斜树前序遍历输出:";
    PreOutput(root);
    cout << endl;
    cout << "中序遍历输出:";
    InOutput(root);
    cout << endl;
    // 只有一个结点的二叉树
    int pre5[] = {  5 };
    int in5[] = { 5 };
    root = Construct(pre5, in5, 1);
    cout << "\n一个结点的二叉树前序遍历输出:";
    PreOutput(root);
    cout << endl;
    cout << "中序遍历输出:";
    InOutput(root);
    cout << endl;
    // 二叉树的根结点指针是NULL
    int pre7[] = { 5 };
    int in7[] = { 5 };
    root = Construct(pre5, in5, 0);

    system("pause");
    return 0;
}

在函数ConstructCore中,先根据前序序列的第一个数字创建根结点,然后在中序序列中找到根结点的位置,这样就能确定左右子树的数量,在前序遍历和中序遍历的序列中划分了左、右子树结点的值后,就可以递归地调用函数ConstructCore,去分别构建它的左右子树。

完整的例子可以查看我的Github

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

spearhead_cai

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值