• 二叉树的重建


    二叉树的三种遍历方式

    1.按照根结点,左子树,右子树的顺序输出结点编号,这称为树的前序遍历(Preorder Tree Walk)

    2.按照左子树,根结点,右子树的顺序输出结点编号,这称为树的中序遍历(Inorder Tree Walk)

    3.按照左子树,右子树,根结点的顺序输出结点编号,这称为树的后序遍历(Postorder Tree Walk)

    所有的遍历方式都是递归的

    注意:二叉树的遍历会对树的每个结点进行一次访问,因此算法复杂度为O(n)。但使用递归实现遍历算法时要注意,一旦树的结点数量庞大且分布不均,很可能导致递归深度过深。

    前序遍历先访问根结点,然后前序遍历左子树,再前序遍历右子树

    中序遍历先遍历根结点的左子树,再访问根结点,最后中序遍历右子树

    后序遍历是从后往前,先左子树,再右子树,最后结点。

    以上三个遍历方法的特点,我们可以总结出来Pre的第一个元素即为二叉树的根,Pro的最后一个元素也为二叉树的根。

    那么已知前序和中序遍历的情况下,设Preorder遍历的当前结点为c,c在in中的位置为m,则m左侧就是c的左子树,右侧就是右子树,然后同理递归。

    举一个例子

    Preorder的输入为pre={1,2,3,4,5,6,7,8,9},Inorder的输入为in={3,2,5,4,6,1,8,7,9};

    例如当前结点为1,其在in中为3 2 5 4 6 [1] 8 7 9,那么当前树的根就是1,左右子数就是3 2 5 4 6和 8 7 9,接下来在3 2 5 4 6组成的树中,Preorder遍历的下一个结点2是根(3 [2] 5 4 6),3和5 4 6 是两个子树,那么我们就可以得到如下图的一个二叉树。

    已知前序和中序遍历,可以确定一棵二叉树。已知中序和后序遍历,可以确定一棵二叉树。但是,已知前序和后序遍历,不能确定一棵二叉树。

    洛谷P1030 求先序排列(已知中序和后序)

    这个题目是根据一棵树的中序和后序排列求出其的先序排列,同上面的方法一样,首先我们还是需要把这个二叉树建立出来。

     先根据样例(第一行为中序,第二行为后序)来看一下解题的思路

    求先序排列其实是一个不断的找根的一个过程,首先我们根据后序遍历的性质可以知道主根为A,那么找到中序遍历中的A,根据中序遍历的性质我们知道A的中序遍历的左子树为B,右子树为DC,对应可以找到A的后序遍历的左子树为B,右子树为DC,那么问题就变成了求

    1.中序遍历B,后序遍历B的树      2.中序遍历DC,后序遍历DC的树

    再根据后序遍历的方法,找到两个根B,和C然后以同样的方法一直递归下去就可以建成整个树。

    再用一个复杂一点的例子

    中序ACGDBHZKX,后序CDGAHXKZB,首先可找到主根B,同理可将中序遍历分为ACGD和HZKX两棵子树,对应可找到后序遍历CDGA和HXKZ

    从而问题就变成求1.中序遍历ACGD,后序遍历CDGA的树 2.中序遍历HZKX,后序遍历HXKZ的树;

    接着递归,按照原先方法,找到1.子根A,再分为两棵子树2.子根Z,再分为两棵子树。一直递归即可

     具体看代码 还不能理解的话用上面的例子手动模拟一遍会更容易理解一些

    里面有用到一些string类的函数这里统一说明

    str.find(x)就是返回元素x在字符串str中第一次出现的位置

    str.substr(pos,n)就是获得一个从pos开始长度为n的字符串str的拷贝(pos的默认值是0,n的默认值是s.size() - pos,即不加参数会默认拷贝整个str)

     1 #include <iostream>
     2 #include <cstring>
     3 #include <string>
     4 #include <algorithm>
     5 #include <queue>
     6 #include <stack>
     7 #include <stdio.h>
     8 #include <cmath>
     9 #include <string.h>
    10 #include <vector>
    11 
    12 #define ll long long
    13 using namespace std;
    14 void solve(string in,string post)//递归找根
    15 {
    16     if(!in.size())
    17     return ;
    18     char root=post[post.size()-1];//找到并且输出根
    19     cout<<root;
    20     int i=in.find(root);//找到根在中序中的位置从而分左右子树
    21     //cout<<i<<endl;
    22     solve(in.substr(0,i),post.substr(0,i));//左子树的中序遍历和后序遍历
    23     solve(in.substr(i+1),post.substr(i,in.size()-i-1));//右子树的中序遍历和后序遍历
    24 }
    25 int main()
    26 {
    27     //freopen("C:\Users\16599\Desktop\in.txt","r",stdin);
    28     string in,post;
    29     cin>>in>>post;
    30     solve(in,post);
    31     return 0;
    32 }

     PS:后期如果做到根据前序和中序输出后序的题目的话会再加进去

  • 相关阅读:
    Bone Collector II(背包 求第k优解)
    How Many Answers Are Wrong (彻底理解带权并查集)
    System Testing(Codeforces Round #543 (Div. 2, based on Technocup 2019 Final Round))D
    Rikka with Minimum Spanning Trees徐州区域赛a题
    cin加速语句
    牛客练习赛41 b 666RPG (01背包)
    js字符串拼接优化
    nodejs中使用递归案例
    thunk的主要用法
    $in的方法总结
  • 原文地址:https://www.cnblogs.com/zlhdbk/p/11272280.html
Copyright © 2020-2023  润新知