剑指offer----007(重建二叉树)

更多题目:《 剑指offer》 目录索引


问题描述

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

思路:
  1. 前序遍历的第一个节点为二叉树的头节点

  2. 根据头节点在中序遍历中找出头节点,并以此为分界点划分左子树和右子树

  3. 由于前序遍历都是先遍历子树的头节点,故此在前序中找左子树的头节点,和右子树的头节点

  4. 根据头节点在中序遍历中找寻分界点,划分左子树和右子树,依次类推

这里写图片描述

代码:

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

}BTNode;

BTNode* BuyBTNode(int x)
{
    BTNode* node = (BTNode*)malloc(sizeof(BTNode));
    assert(node);
    node->_data = x;
    node->_left = NULL;
    node->_right = NULL;

    return node;
}




BTNode*  Construct(int* prev, int* inorder, int len)
{
    if (prev == NULL || inorder == NULL || len < 0)
        return NULL;
    return ConstructCore(prev, prev + len - 1, inorder, inorder + len - 1);
}


BTNode* ConstructCore(int* startPreorder, int* endPreorder, int* startInorder, int* endInorder)
{

    //前序的第一个值为根节点
    BTNode* root = BuyBTNode(*startPreorder);

    //在中序中找根,以该值为分界点,左边为左子树,右边为右子树
    int value = *startPreorder;
    int* inorder = startInorder;
    while (inorder <= endInorder)
    {
        if (value == *inorder)
        {
            break;
        }
        inorder++;
    }

    //保存左子树长度
    int leftlen = inorder - startInorder;

    //保存右子树根,中序找到根后,左边为左子树,对应前序中除去根节点和左子树,即为右子树的第一个节点
    int* righttree = startPreorder + leftlen ;

    //创建左子树,左子树的前序为,第二个+节点数(长度),中序为第一个节点---根节点的前一个
    if (leftlen > 0)
    {
        root->_left = ConstructCore(startPreorder + 1, righttree, startInorder, inorder-1);

    }

    //创建右子树,前序为,根节点+左子树节点(长度)-----最后,中序为根节点的下一个----最后
    if (leftlen < endPreorder - startPreorder)
    {
        root->_right = ConstructCore(righttree + 1, endPreorder, inorder + 1, endInorder);
    }

    return root;

}


void Test()
{

    BTNode* root;
    int prevorder[] = { 1, 2, 4, 7, 3, 5, 6, 8 };
    int inoeder[] = { 4, 7, 2, 1, 5, 3, 8, 6 };

    int len = sizeof(prevorder) / sizeof(prevorder[0]);
    root = Construct(prevorder, inoeder, len);

    printf("%d\n", root->_data);
}


void Test1()
{
    const int length = 5;
    int preorder[length] = { 1, 2, 3, 4, 5 };
    int inorder[length] = { 5, 4, 3, 2, 1 };

    BTNode* root = Construct(preorder, inorder, length);

    printf("%d\n", root->_data);

}

void Test2()
{
    const int length = 5;
    int preorder[length] = { 1, 2, 3, 4, 5 };
    int inorder[length] = { 1, 2, 3, 4, 5 };

    BTNode* root = Construct(preorder, inorder, length);

    printf("%d\n", root->_data);

}

void Test3()
{
    const int length = 1;
    int preorder[length] = { 1 };
    int inorder[length] = { 1 };

    BTNode* root = Construct(preorder, inorder, length);

    printf("%d\n", root->_data);

}

void Test4()
{
    BTNode* root = Construct(NULL, NULL, 0);

}
int main()
{
    Test();
    Test1();
    Test2();
    Test3();
    Test4();

    system("pause");
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值