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


轉至:https://www.cnblogs.com/xinchrome/p/4905608.html

現在有一個問題,已知二叉樹的前序遍歷和中序遍歷:
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