• 【剑指offer】面试题六:重建二叉树


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

    二叉树结点的定义如下:

    typedef struct Node
    {
        int m_nValue;
        struct Node* n_pLeft;
        struct Node* m_pRIght 
    }BinaryTreeNode, *PBinaryTreeNode;

    重建的结果如下图所示:

    分析:

    在二叉树的前序遍历序列中,第一个数字总是树的根结点的值。但在中序遍历序列中。根结点的值在序列的中间,左子树的所有结点的值位于根结点的值的左边,而右子树的所有结点的值位于根结点的值的右边。因此我们可以得出如下一般的步骤:
    1、扫描前序遍历的第一个值(假设为value),找到value在其中序遍历中的位置;
    2、通过步骤 1,可知该二叉树的根结点和根结点的左子树与右子树;
    3、让左子树与右子树分别重复步骤 14、直到左右子树全部遍历完,便可得到该二叉树。

    我们可以分析题目中给出的示例:

    1、全部结点的前序遍历序列和中序遍历序列:
     前序序列:{1,2,4,7,3,5,6,8}

     中序序列:{4,7,2,1,5,3,8,6}

     前序遍历的第一个数字 1 就是根结点的值。然后扫描中序遍历,就能确定根结点的值的位置。根据中序遍历的特点,在根结点的值 1  前面的三个数字 4,、7、2 都是左子树结点的值,位于 1 后面的数字 5,3,8,6 都是右子树结点的值。

    2、根结点左子树的前序遍历序列和中序遍历序列:

     前序序列:{2,4,7}

     中序序列:{4,7,2}

     由于前序遍历的第一个数字就是左子树的根结点的值,即为 2。从而遍历左子树的中序序列找到 2 的位置,而在中序序列中位于 2 左边的就是根结点左子树的左子树,位于 2 右边的就是根结点左子树的右子树。由中序序列{4,7,2}可知,该子树只有左子树,没有右子树。

    3、根结点右子树的前序遍历序列和中序遍历序列:

     前序序列:{3,5,6,8}

     中序序列:{5,3,8,6}

     步骤与2类似,不在赘述。

    经过分析可知,既然我们已经分别找到了左、右子树的前序遍历序列和中序遍历序列,我们可以用同样的方法分别取构建左右子树。也就是说,接下来的事情可以用递归的方法去完成。

    在分析清楚之后,我们可以用递归的方式去实现该题,代码如下:

      1 // construct.cpp
      2 #include "stdio.h"
      3 #include "stdlib.h"
      4 #include <stdexcept>
      5 
      6 typedef struct Node
      7 {
      8     int m_nValue;
      9     struct Node *m_pLeft;
     10     struct Node *m_pRight;
     11 }BTreeNode, *pBTreeNode;
     12 
     13 BTreeNode *constructCore(int *preOrderStart, int *preOrderEnd,
     14     int *inOrderStart, int *inOrderEnd);
     15 
     16 BTreeNode *construct(int *preOrder, int *inOrder, int len)
     17 {
     18     if(preOrder == NULL || inOrder == NULL || len <= 0)
     19         return NULL;
     20 
     21     return constructCore(preOrder, preOrder + len - 1,
     22             inOrder, inOrder + len - 1);
     23 }
     24 
     25 // 建树 (前序开始、前序结束、中序开始、中序结束)
     26 BTreeNode *constructCore(int *preOrderStart, int *preOrderEnd,
     27     int *inOrderStart, int *inOrderEnd)
     28 {
     29     int rootVal = preOrderStart[0];
     30 
     31     BTreeNode *root = (BTreeNode*)malloc(sizeof(BTreeNode));
     32     root->m_nValue = rootVal;
     33     root->m_pLeft = root->m_pRight = NULL;
     34 
     35     // 递归结束的条件
     36     if(preOrderStart == preOrderEnd)
     37     {
     38         if(inOrderStart == inOrderEnd && *preOrderStart == rootVal)
     39             return root;
     40         else
     41             throw std::out_of_range("Invalid Input");
     42     }
     43 
     44     // 遍历中序序列
     45     int *rootInOrder = inOrderStart;
     46     while(rootInOrder < inOrderEnd && *rootInOrder != rootVal)
     47         ++rootInOrder;
     48 
     49     if(rootInOrder == inOrderEnd && *rootInOrder != rootVal)
     50         throw std::out_of_range("Invalid Input");
     51 
     52     int leftLen = rootInOrder - inOrderStart;
     53     int *leftPreOrderEnd = preOrderStart + leftLen;
     54 
     55     if(leftLen > 0) // 存在左子树
     56     {
     57         // 构建左子树
     58         root->m_pLeft = constructCore(preOrderStart + 1, leftPreOrderEnd,
     59             inOrderStart, rootInOrder - 1);
     60     }
     61     if(leftLen < preOrderEnd - preOrderStart) // 存在右子树
     62     {
     63         // 构建右子树
     64         root->m_pRight = constructCore(leftPreOrderEnd + 1, preOrderEnd,
     65             rootInOrder + 1, inOrderEnd);
     66     }
     67     return root;
     68 }
     69 
     70 void preOrderTr(BTreeNode *root) // 先序遍历
     71 {
     72     if(root != NULL)
     73     {
     74         printf("%2d", root->m_nValue);
     75         preOrderTr(root->m_pLeft);
     76         preOrderTr(root->m_pRight);
     77     }
     78 }
     79 
     80 void inOrderTr(BTreeNode *root) // 中序遍历
     81 {
     82     if(root != NULL)
     83     {
     84         inOrderTr(root->m_pLeft);
     85         printf("%2d", root->m_nValue);
     86         inOrderTr(root->m_pRight);
     87     }
     88 }
     89 
     90 void postOrderTr(BTreeNode *root) // 后序遍历
     91 {
     92     if(root != NULL)
     93     {
     94         postOrderTr(root->m_pLeft);
     95         postOrderTr(root->m_pRight);
     96         printf("%2d", root->m_nValue);
     97     }
     98 }
     99 
    100 int main(int argc, char *argv[])
    101 {
    102     BTreeNode *root = NULL;
    103 
    104     int preOrder[] = {1, 2, 4, 7, 3, 5, 6, 8};
    105     int inOrder[] = {4, 7, 2, 1, 5, 3, 8, 6}; 
    106 
    107     root = construct(preOrder, inOrder, 8);
    108     printf("root value: %d
    ", root->m_nValue);
    109 
    110     printf("先序遍历序列
    ");
    111     preOrderTr(root);
    112 
    113     printf("
    中序遍历序列
    ");
    114     inOrderTr(root);
    115 
    116     printf("
    后序遍历序列
    ");    
    117     postOrderTr(root);    
    118     printf("
    ");
    119 
    120     return 0;
    121 }
    View Code

    编译与执行:

    1 g++ -o construct construct.cpp
    2 ./construct

    本文完。

  • 相关阅读:
    Hadoop与分布式开发
    Hadoop体系结构
    MapReduce基本流程与设计思想初步
    hadoop集群启动时DataNode节点启动失败
    初识Hadoop
    国家标准免费下载网站大全
    Effective C++ 之 Item 3:尽可能使用 const
    Effective C++ 之 Item 2:尽量以 const, enum, inline 替换 #define
    Effective C++ 之 Item 1: 视C++为一个语言联邦
    Effective C++ 之 0 导读(Introduction)
  • 原文地址:https://www.cnblogs.com/xfxu/p/4574846.html
Copyright © 2020-2023  润新知