根據二叉樹的中序遍歷和前序遍歷,還原二叉樹


如今有一個問題,已知二叉樹的前序遍歷和中序遍歷:
PreOrder:         GDAFEMHZ
InOrder:            ADEFGHMZ
咱們如何還原這顆二叉樹,並求出他的後序遍歷?node

 

咱們基於一個事實:中序遍歷必定是 { 左子樹中的節點集合 },root,{ 右子樹中的節點集合 },前序遍歷的做用就是找到每顆子樹的root位置。ios

算法1
輸入:前序遍歷,中序遍歷
一、尋找樹的root,前序遍歷的第一節點G就是root。
二、觀察前序遍歷GDAFEMHZ,知道了G是root,剩下的節點必然在root的左或右子樹中的節點。
三、觀察中序遍歷ADEFGHMZ。其中root節點G左側的ADEF必然是root的左子樹中的節點,G右側的HMZ必然是root的右子樹中的節點,root不在中序遍歷的末尾或開始就說明根節點的兩顆子樹都不爲空。
四、觀察左子樹ADEF,按照前序遍歷的順序來排序爲DAFE,所以左子樹的根節點爲D,而且A是左子樹的左子樹中的節點,EF是左子樹的右子樹中的節點。
五、一樣的道理,觀察右子樹節點HMZ,前序爲MHZ,所以右子樹的根節點爲M,左子節點H,右子節點Z。算法

觀察發現,上面的過程是遞歸的。先找到當前樹的根節點,而後劃分爲左子樹,右子樹,而後進入左子樹重複上面的過程,而後進入右子樹重複上面的過程。最後就能夠還原一棵樹了:數組

從而獲得PostOrder:       AEFDHZMG
改進:
更進一步說,其實,若是僅僅要求寫後續遍歷,甚至不要專門佔用空間保存還原後的樹。只須要用一個數組保存將要獲得的後序,就能實現:spa

算法2
輸入:一個保存後序的數組,前序遍歷,中序遍歷
一、肯定根,放在數組末尾
二、肯定左子樹的索引範圍,放在數組中相同索引的位置。
三、肯定右子樹索引範圍,放在數組中對應索引的位置,恰好能放下。
四、用左子樹的前序遍歷和中序遍歷,把後序遍歷保存在對應索引的位置
五、用左子樹的前序遍歷和中序遍歷,把後序遍歷保存在對應索引的位置code

 

引伸問題blog

一樣咱們能夠用中序遍歷和後序遍歷還原這顆樹。排序

然而,若是是前序遍歷和後序遍歷,就不可以還原這棵樹了,由於沒法找到中間點,注意下面這兩種狀況:遞歸

  

兩棵樹的前序是相同的,兩棵樹的後序也是相同的。換句話說,若是有一顆子樹,它的根節點的一個子樹是空樹,那麼就沒法斷定那一個子樹是空樹。索引

 

 


上算法1和算法2的代碼:

 

//算法1

#include <iostream>
#include <fstream>
#include <string>

struct TreeNode
{
  struct TreeNode* left;
  struct TreeNode* right;
  char  elem;
};


TreeNode* BinaryTreeFromOrderings(char* inorder, char* preorder, int length)
{
  if(length == 0)
    {
      return NULL;
    }
  TreeNode* node = new TreeNode;
  node->elem = *preorder;
  int rootIndex = 0;
  for(;rootIndex < length; rootIndex++)
    {
      if(inorder[rootIndex] == *preorder)
      break;
    }
  node->left = BinaryTreeFromOrderings(inorder, preorder +1, rootIndex);
  node->right = BinaryTreeFromOrderings(inorder + rootIndex + 1, preorder + rootIndex + 1, length - (rootIndex + 1));
  std::cout<<node->elem<<std::endl;
 free(node);
return NULL; } int main(int argc, char** argv){ char* pr="GDAFEMHZ"; char* in="ADEFGHMZ"; BinaryTreeFromOrderings(in, pr, 8); printf("\n"); return 0;}

 

題目只要求輸出後續遍歷,能夠直接把當前節點的value保存在一個char中。

#include <stdio.h>
#include <stdio.h>
#include <iostream>
using namespace std;
struct TreeNode
{
  struct TreeNode* left;
  struct TreeNode* right;
  char  elem;
};

void BinaryTreeFromOrderings(char* inorder, char* preorder, int length)
{
  if(length == 0)
    {
      //cout<<"invalid length";
      return;
    }
  char node_value = *preorder;
  int rootIndex = 0;
  for(;rootIndex < length; rootIndex++)
    {
      if(inorder[rootIndex] == *preorder)
      break;
    }
  //Left
  BinaryTreeFromOrderings(inorder, preorder +1, rootIndex);
  //Right
  BinaryTreeFromOrderings(inorder + rootIndex + 1, preorder + rootIndex + 1, length - (rootIndex + 1));
  cout<<node_value<<endl;
  return;
}


int main(int argc, char* argv[])
{
    printf("Hello World!\n");
    char* pr="GDAFEMHZ";
    char* in="ADEFGHMZ";
  
    BinaryTreeFromOrderings(in, pr, 8);

    printf("\n");
    return 0;
}
相關文章
相關標籤/搜索