前言:
說到二叉樹,我之前寫過一篇博客,講的就是二叉樹的遍歷,但是爲什麼再講一遍呢?
當然,因爲不同。這也解決了我之前關於樹的一個疑惑。我當時建樹的時候是前序建樹,只有前序遍歷的結果,並不能唯一的確定一棵二叉樹,因而我採用了類似 a b null null c null null 的形式來確定化其樹的形態,而一旦知道了中序遍歷還有(前序遍歷和後序遍歷)的任何一個,就可以確定其二叉樹形態,因而就只寫序列就可以了,而不需要再用null。
問題:
知道一棵二叉樹的前序遍歷和中序遍歷求其後序遍歷。
輸入:
ABC
BAC
FDXEAG
XDEFAG
原理:
首先前序遍歷(根左右)的第一個元素肯定是根節點,那麼通過尋找中序遍歷(左根右)中根節點的位置,就可以把
中序序列分爲左右子樹,假設其長度爲l和r,那麼其前序遍歷的序列長度可以表示爲:1+l+r ,分別代表根,左子樹,右子樹。
同理,分別對左右子樹進行同等操作,就可以確定二叉樹的形態。
當然,後序遍歷和中序遍歷也適用。
Ok,let‘s see the code now !
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
//二叉樹遍歷。
//前序+中序確定一棵樹。
//同理:後序+中序確定一棵樹。
/*
思想:
前序和後序能確定根節點的位置,
通過查找中序遍歷根節點的位置,可以確定其左右子樹,
對其左右子樹進行同樣的操作,遞歸即得二叉樹的形態。
*/
using namespace std;
string sPre,sIn;//前序遍歷和中序遍歷的字符串。
struct node{
char weight;
node* lChild;
node* rChild;
};
node* buildTree(int s1,int e1,int s2,int e2)
{
node* root=new node({sPre[s1],NULL,NULL});
int rootId;
for(int i=s2;i<=e2;i++)//尋找中序遍歷root結點的位置
{
if(sIn[i]==sPre[s1])
{
rootId=i;
break;
}
}
if(rootId!=s2)//如果中序遍歷的根節點前面有結點肯定是其左子樹,其結點個數爲rootId-s2
{
root->lChild=buildTree(s1+1,s1+rootId-s2,s2,rootId-1);
}
if(rootId!=e2)//同理,中序遍歷根節點後面有結點肯定是其右子樹,結點數爲e2-rootId
{
root->rChild=buildTree(e1-e2+rootId+1,e1,rootId+1,e2);
}
return root;
}
void postOrder(node* root)
{
if(root->lChild!=NULL)
postOrder(root->lChild);
if(root->rChild!=NULL)
postOrder(root->rChild);
cout<<root->weight;
}
int main()
{
while(cin>>sPre>>sIn)
{
node*root=buildTree(0,sPre.length()-1,0,sIn.length()-1);
postOrder(root);
cout<<endl<<endl;
}
return 0;
}
結果:
總結:
本身題目並不難,但是解決了自己的一個疑問,很值!