数据结构与算法学习笔记——二叉树重构(递归)

关于二叉树的另外一个重要内容就二叉树的重构,二叉树的重构就是根据已知的二叉树前序,中序,后续遍历的数组重新构造出园二叉树。
对于普通的二叉树可以由 前序遍历+中序遍历 或者 后序遍历+中序遍历 重构(注意:二叉树各节点不能有相同值)。
对于只知道 前序遍历和后续遍历是否可以进行二叉树重构呢?对于普通二叉树以上两个条件是无法重构二叉树的,比如:

   1             1          
  /             /
 2             2
   \            \
    3            3
   /              \
  4                4

以上两个不同的二叉树他们的
前序遍历:1 2 3 4;
后序遍历:4 3 2 1;
相同,所以可以看出对于一般的二叉树仅仅知道前序和后序遍历是不够的,因为对于有些节点无无法判断出是左节点还是右节点。但是如果提前已知该二叉树是满二叉树(full binary tree)那可以根据前序和后序遍实现对二叉树重构,后面我会再对这个内容进行整理。
以下例对二叉树进行重构:

              1
           /     \  
          2       3
        /   \   /    \
      4      5 6      7
            / \        \
           8   9        10

前序遍历:1 2 4 5 8 9 3 6 7 10;
中序遍历:4 2 8 5 9 1 6 3 7 10;
后续遍历:4 8 9 5 2 6 10 7 3 1;

前序遍历+中序遍历重构二叉树

前序遍历的顺序是:根->左子树->右子树
中序遍历的顺序是:左子树->根->右子树;

因此前序遍历的第一个元素1就是整个二叉树的根节点;
在中序遍历中找到该元素,则该元素把中序遍历数组分成左右两部分,分别为左子树(4 2 8 5 9)和右子树(6 3 7 10);
前序遍历的第二个元素2为左子树的根节点,同理在中序遍历中找到该元素,左子树又被一分为二(4)和(8 5 9);
……
如此递归下去直到最后一个元素;
代码如下:

Node* RebuildTree_Pre_In(int preorder[], int inorder[], int inorder_left, int inorder_right, int &pre_index){
    if(inorder_left > inorder_right)
        return NULL;
    int key = preorder[pre_index++];
    Node *node = new Node(key);
    if(inorder_left == inorder_right)
        return node;
    int i;
    for(i = inorder_left; inorder[i] != key; ++i);
    node->left = RebuildTree_Pre_In(preorder, inorder, inorder_left, i-1, pre_index);
    node->right = RebuildTree_Pre_In(preorder, inorder, i+1, inorder_right, pre_index);
    return node;
}

后序遍历+中序遍历重构二叉树

后序遍历的顺序是:左子树->右子树->根;
中序遍历的顺序是:左子树->根->右子树;
和前面相似,不同的是对于后序遍历我们从最后一个元素下手。
后续遍历数组的最后一个元素 1 就是整个数组的根节点;
在中序遍历数组中查找到该元素同样把整个数组分成两部分,左子树(4 2 8 5 9)和右子树(6 3 7 10);
后续遍历数组的倒数第二个元素 3 就是右子树的根节点,同样又把上述右子树分成左右两部分(6)和(7 10);
…….
如此地递归至最后一个元素。
注意,我们在后序遍历数组是从根节点到右子树的顺序取值的,所以在递归的时候也要先从右节点开始。
代码如下:

Node* RebuildTree_In_Post( int inorder[], int postorder[], int inorder_left, int inorder_right, int &post_index){
    if(inorder_left > inorder_right)
        return NULL;
    int key = postorder[post_index--];
    Node *node = new Node(key);
    if(inorder_left == inorder_right)
        return node;
    int i;
    for(i = inorder_left; inorder[i] != key; ++i);      
    node->right= RebuildTree_In_Post(inorder, postorder, i+1, inorder_right, post_index);
    node->left = RebuildTree_In_Post(inorder, postorder, inorder_left, i-1, post_index);

    return node;
}

测试代码如下:

//reconstruct a binary by preorder ang inorder traversal
    int  preorder[] = {1,2,4,5,8,9,3,6,7,10};
    int   inorder[] = {4,2,8,5,9,1,6,3,7,10};
    int postorder[] = {4,8,9,5,2,6,10,7,3,1};
    int pre_index = 0;
    int post_index = 9;
    cout << "\n--------------- rebuild tree:--------------------\n";
    cout << "rebuild from preorder and inorder traversal:\n";
    Tree reTree1(RebuildTree_Pre_In(preorder, inorder, 0, 9, pre_index));   
    reTree1.StackPreorder();
    std::cout << endl;
    reTree1.StackInorder();
    std::cout << endl;
    reTree1.StackPostorder();
    std::cout << endl;
    cout << "rebuild from preorder and inorder traversal:\n";
    Tree reTree2(RebuildTree_In_Post(inorder, postorder, 0, 9, post_index));    
    reTree2.StackPreorder();
    std::cout << endl;
    reTree2.StackInorder();
    std::cout << endl;
    reTree2.StackPostorder();
    std::cout << endl;   

测试结果:
这里写图片描述

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值