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



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

 

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

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

觀察發現,上面的過程是遞歸的。先找到當前樹的根節點,然后划分為左子樹,右子樹,然后進入左子樹重復上面的過程,然后進入右子樹重復上面的過程。最后就可以還原一棵樹了:

從而得到PostOrder:       AEFDHZMG
改進:
更進一步說,其實,如果僅僅要求寫后續遍歷,甚至不要專門占用空間保存還原后的樹。只需要用一個數組保存將要得到的后序,就能實現:

算法2
輸入:一個保存后序的數組,前序遍歷,中序遍歷
1、確定根,放在數組末尾
2、確定左子樹的索引范圍,放在數組中相同索引的位置。
3、確定右子樹索引范圍,放在數組中對應索引的位置,剛好能放下。
4、用左子樹的前序遍歷和中序遍歷,把后序遍歷保存在對應索引的位置
5、用左子樹的前序遍歷和中序遍歷,把后序遍歷保存在對應索引的位置

 

引申問題

同樣我們可以用中序遍歷和后序遍歷還原這顆樹。

然而,如果是前序遍歷和后序遍歷,就不能夠還原這棵樹了,因為無法找到中間點,注意下面這兩種情況:

  

兩棵樹的前序是相同的,兩棵樹的后序也是相同的。換句話說,如果有一顆子樹,它的根節點的一個子樹是空樹,那么就無法判定那一個子樹是空樹。

 

 


上算法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;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM