zoukankan      html  css  js  c++  java
  • 二叉树重建[UVA-536]

    二叉树重建Tree Recovery(UVA-536,ULM1997)

     时间限制3000ms

    分别是书上习题6-3,涉及到二叉树这一数据结构中已知两种遍历求整个树的过程。

    首先需要复习一下二叉树的前序遍历和中序遍历和后序遍历。二叉树的前序遍历是指,先输出根结点的值,然后依次递归调用遍历左右子树;中序遍历是指,先递归遍历左子树,然后输出根结点的值,然后递归遍历右子树;后续遍历是指,先递归遍历左右子树,然后输出根结点的值。下面的解题分析都是以此为基础的。

    以第一个样例输入为例:

    先序遍历:DBACEGF

    中序遍历:ABCDEFG

    前面提到,前序遍历首先会输出当前子树的根结点,因此位于前序遍历的第一个元素D,一定是当前树的根。而在中序遍历中,根在中间输出,因而在中序遍历中查找根D,将整个中序遍历分为了两大部分:分别是树的左子树和右子树,如下所示

         D

       /  

    (ABC) (EFG)

    那左右子树又该如何得到呢?很容易想到用递归的方法来构建,也就是利用了自顶向下的求解思路。左右子树的中序遍历很容易得到(利用找到的根的位置将其一分为二),而如何得到在原前序遍历中的子树呢?我们知道,前序遍历在输出根结点后,依次输出其左右的结点,所以关键的一步在于确定左右子树的结点个数。而利用之前中序遍历找到的根的位置,不难确定其个数。因此整个重建的算法就很明了了。剩下的问题就是如何确定递归出口。也很简单,只要输入时的数组只有一个元素,即对应的树没有孩子,那么该结点实际就是原树的一个叶子,递归也就结束了。整个过程的时间为$O(n^2)$。

    我的的C++代码如下:(我的二叉树是按照《算法导论》一书中的描述定义的,包含了父节点。所以需要额外的处理一下。)

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<cstring>
     4 template<typename T>
     5 struct treenode
     6 {
     7     T value;
     8     treenode * leftchild;
     9     treenode * rightchild;
    10     treenode * parent;
    11     treenode()
    12     {
    13         value = 0; leftchild = rightchild = parent = nullptr;
    14     }
    15     treenode(int v) :value(v)
    16     {
    17         leftchild = rightchild = parent = nullptr;
    18     }
    19 };
    20 template<typename T>
    21 int search(T A[], T value, int size)
    22 {
    23     int i;
    24     for (i = 0; i < size; i++)
    25         if (A[i] == value)
    26             return i;
    27     return -1;
    28 }
    29 template<typename T>
    30 treenode<T> * treerecovery(T inorder[], T postorder[], int size)
    31 {
    32     if (size == 1)
    33         return new treenode<T>(inorder[0]);
    34     int pos = search(inorder, postorder[0], size);
    35     treenode<T> * ptleft = nullptr;
    36     treenode<T> * ptright = nullptr;
    37     treenode<T> * ptthis = new treenode<T>(postorder[0]);
    38     if (pos != 0)
    39     {
    40 
    41         ptleft = treerecovery(inorder, postorder + 1, pos);
    42         ptleft->parent = ptthis;
    43     }
    44     if (pos != size - 1)
    45     {
    46         ptright = treerecovery(inorder + pos + 1, postorder + pos + 1, size - pos - 1);
    47         ptright->parent = ptthis;
    48     }
    49     ptthis->leftchild = ptleft;
    50     ptthis->rightchild = ptright;
    51     return ptthis;
    52 }
    53 template<typename T>
    54 void traversep(treenode<T> * tn)
    55 {
    56     if (tn == nullptr)
    57         return;
    58     treenode<T> * pt = tn;
    59     traversep(tn->leftchild);
    60     traversep(tn->rightchild);
    61     std::cout << tn->value;
    62 }
    63 int main()
    64 {
    65 #define TMAX 30
    66     char A[TMAX];
    67     char B[TMAX];
    68     while (std::cin >> A)
    69     {
    70         std::cin >> B;
    71         int len = strlen(A);
    72         treenode<char> * tree = treerecovery(B, A, len);
    73         traversep(tree);
    74         std::cout << std::endl;
    75     }
    76     return 0;
    77 }

    需要说明的是,必须要有中序遍历,才能够确定唯一的二叉树。换言之,只有前序和后序遍历是无法得到唯一确定的二叉树的。为什么呢?理由很简单,没有办法确定这个树左右节点是不是满的。以输入用例为例,只知道根节点D,剩余的元素,完全可以作为单纯的左子树或者右子树,也可以作为两支。

     

  • 相关阅读:
    hadoop学习摘要
    尝试加载 Oracle 客户端库时引发 BadImageFormatException。如果在安装 32 位 Oracle 客户端组件的情况下以 64 位模式运行,将出现此问题。
    sqlserver 2012 IDE中 Windows身份验证连接服务器报错 ,Login failed for user 'xxxAdministrator'. 原因: 找不到与提供的名称匹配的登录名。
    不重复随机数列生成算法
    异步和等待(async和await)
    mvc和mvvm的区别?
    Redis命令大全
    Java NIO 三大组件之 Buffer
    Java NIO 三大组件之 Channel
    Java NIO概述
  • 原文地址:https://www.cnblogs.com/ggggg63/p/6750279.html
Copyright © 2011-2022 走看看