《剑指offer》面试题07:重建二叉树

更多剑指offer面试习题请点击: 《剑指offer》(第二版)题集目录索引

题目:
  输入某二叉树的前序遍历和中序遍历结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{ 1, 2, 4, 7, 3, 5, 6, 8 }和中序遍历序列{ 4, 7, 2, 1, 5, 3, 8, 6 },则重建的二叉树如图所示:
这里写图片描述


解题思路:
  我们知道前序遍历的第一个节点一定是这棵树的根节点,根据这个根节点和二叉树的树的中序遍历序列,可以得到这颗树的左子树、右子树。这样我们就确定了这颗树的根节点,那么根节点的左、右节点又如何确定呢?
  这时候采用递归思想,把左右子树看作一棵完整的树,根据前序序列可以得到左右子树的根节点,也就是这颗树的根节点的左右孩子节点。就这样一直递归就能构建出这颗二叉树。

这里写图片描述


< code >

typedef struct BinaryTreeNode
{
    struct BinaryTreeNode* _left;
    struct BinaryTreeNode* _right;
    int _data;
}BTNode;


/*
 *功能:打印二叉树的前序遍历
 *参数:root——二叉树的根节点
 *返回值:无
*/
void BTreePrevOrder(BTNode* root) //前序遍历
{
    if (NULL == root)
    {
        return;
    }
    printf("%d ", root->_data);
    BTreePrevOrder(root->_left);
    BTreePrevOrder(root->_right);
}

/*
*功能:创建节点
*参数:x——节点的值
*返回值:节点的地址
*/
BTNode* BuyBTNode(int x) //创建节点
{
    BTNode* node = (BTNode*)malloc(sizeof(BTNode));
    assert(node != NULL);

    node->_left = NULL;
    node->_right = NULL;
    node->_data = x;

    return node;
}

/*
*功能:递归构建二叉树
*参数:
    pre_arry——前序遍历
    pr_start——前序遍历开始的位置
    pr_end  ——前序遍历结束的位置
    in_arry ——中序遍历
    in_start——中序遍历开始的位置
    in_end  ——中序遍历结束的位置
*返回值:当前树的根节点地址
*/
BTNode* Reconstruction(int* pre_arry, int pr_start, int pr_end, int* in_arry, int in_start, int in_end)
{
    if (pr_start > pr_end || in_start > in_end)
        return NULL;

    BTNode* root = BuyBTNode(pre_arry[pr_start]);

    int i = in_start;
    for (; i <= in_end; i++)
    {
        if (in_arry[i] == pre_arry[pr_start])
        {
            root->_left = Reconstruction(pre_arry, pr_start + 1, pr_start + i - in_start, in_arry, in_start, i - 1);
            root->_right = Reconstruction(pre_arry, pr_start + i - in_start + 1, pr_end, in_arry, i + 1, in_end);
        }
    }
    return root;
}

/*
*功能:重建二叉树
*参数:
    pre_arry——前序遍历
    in_arry ——中序遍历
    length  ——序列长度

*返回值:重建后的二叉树的根节点地址
*/
BTNode* ConstructBinaryTree(int* pre_arry, int* in_arry, int length) //重建二叉树
{
    if (pre_arry == NULL || in_arry == NULL || length <= 0)
        return NULL;

    return Reconstruction(pre_arry, 0, length - 1, in_arry, 0, length - 1);
}

< 测试code >

/*
*功能:测试程序
*参数:
    testName——测试名
    pre_arry ——前序遍历
    in_arry  ——中序遍历
    length_pr——前序遍历长度
    length_in——中序遍历长度

*返回值:无
*/
void Test(char* testName, int* pre_arry, int* in_arry, int length_pr, int length_in)
{
    if (length_pr != length_in)
    {
        return;
    }
    if (testName == NULL)
    {
        return;
    }

    printf("%s:\n", testName);

    BTNode* root = ConstructBinaryTree(pre_arry, in_arry, length_pr);
    printf("重建的二叉树的前序序列:");
    BTreePrevOrder(root);
    printf("\n");

    printf("输入的二叉树的前序序列:");
    if (pre_arry != NULL)
    {
        int i = 0;
        for (; i < length_pr; ++i)
        {
            printf("%d ", pre_arry[i]);
        }
    }
    printf("\n===============================================================\n\n");
}

//完全二叉树
void test1() 
{
    int pre_arry[] = { 1, 2, 4, 8, 5, 3, 6, 7 }; //前
    int in_arry[] = { 8, 4, 2, 5, 1, 6, 3, 7 };  //中
    int length_pr = sizeof(pre_arry) / sizeof(pre_arry[0]);
    int length_in = sizeof(in_arry) / sizeof(in_arry[0]);
    Test("test1",pre_arry, in_arry, length_pr, length_in);
}

//非完全二叉树
void test2()
{
    int pre_arry[] = { 1, 2, 4, 5, 3, 7 }; //前
    int in_arry[] = { 4, 2, 5, 1, 3, 7 };  //中
    int length_pr = sizeof(pre_arry) / sizeof(pre_arry[0]);
    int length_in = sizeof(in_arry) / sizeof(in_arry[0]);
    Test("test2", pre_arry, in_arry, length_pr, length_in);
}

//所有节点都没有右节点的二叉树
void test3()
{
    int pre_arry[] = { 1, 2, 3, 4, 5, 6 }; //前
    int in_arry[] = { 6, 5, 4, 3, 2, 1 };  //中
    int length_pr = sizeof(pre_arry) / sizeof(pre_arry[0]);
    int length_in = sizeof(in_arry) / sizeof(in_arry[0]);
    Test("test3", pre_arry, in_arry, length_pr, length_in);
}

//所有节点都没有左节点的二叉树
void test4()
{
    int pre_arry[] = { 1, 2, 3, 4, 5, 6 }; //前
    int in_arry[] = { 1, 2, 3, 4, 5, 6 };  //中
    int length_pr = sizeof(pre_arry) / sizeof(pre_arry[0]);
    int length_in = sizeof(in_arry) / sizeof(in_arry[0]);
    Test("test4", pre_arry, in_arry, length_pr, length_in);
}

//只有一个节点的二叉树
void test5()
{
    int pre_arry[] = { 1 }; //前
    int in_arry[] = { 1 };  //中
    int length_pr = sizeof(pre_arry) / sizeof(pre_arry[0]);
    int length_in = sizeof(in_arry) / sizeof(in_arry[0]);
    Test("test5", pre_arry, in_arry, length_pr, length_in);
}

//只有一个节点的二叉树
void test6()
{
    int* pre_arry = NULL; //前
    int* in_arry = NULL;  //中
    int length_pr = sizeof(pre_arry) / sizeof(pre_arry[0]);
    int length_in = sizeof(in_arry) / sizeof(in_arry[0]);
    Test("test6", pre_arry, in_arry, length_pr, length_in);
}

//前序序列和中序序列不匹配
void test7()
{
    int pre_arry[] = { 1, 2, 4, 7, 3, 5, 6, 8 }; //前
    int in_arry[] = { 4, 7, 2, 1, 6, 3, 8, 5 };  //中
    int length_pr = sizeof(pre_arry) / sizeof(pre_arry[0]);
    int length_in = sizeof(in_arry) / sizeof(in_arry[0]);
    Test("test7", pre_arry, in_arry, length_pr, length_in);
}

运行截图:
这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值