輸入某二叉樹的前序走訪和中序遍曆的結果,請重建出該二叉樹。假設輸入的前序序列和中序序列的結果都不含重複的數字,例如輸入前序序列{1,2,4,7,3,5,6,8}和中序序列{4,7,2,1,5,3,8,6},則重建樹並輸出它的頭結點,二叉樹的頭結點定義如下:
struct BinaryTreeNode{
int m_value;
BinryTreeNode *pleft;
BinaryTreeNode *pright;
}
其實對於二叉樹的各種遍曆演算法的具體實現難度遠遠大於理解,對我來說在上資料結構課時,就對前、中、後三種遍曆思想有自認為還可以的理解(也就是說給我一棵樹,我絕對可以準確的寫出它的三種遍曆序列,也可通過已知的前(後)序列和中序序列重新畫出這棵樹),但到了具體的代碼實現就比較懵逼了。。。對遞迴這種需要在腦子中像電腦一樣跑N遍的方式好難準確無誤的推敲啊。。。每次遇到遞迴的演算法就很尷尬,看的懂但是不會自己寫,導致自己的動態規划算法學的很爛0.0,所以對於遞迴還得加強學習啊。。。
如果理解了遞迴的訪問,那麼建樹的過程就容易多了,前序走訪序列的第一個數(後序遍曆的最後一個數)一定是根結點,所以可以根據此結點在中序序列中的位置把中序序列分為左子樹和右子數兩個部分,同樣的道理,在左子樹和右子數中同樣可以用到這樣的規律來確定每個中間結點。
public class Solution { public TreeNode reConstructBinaryTree(int [] pre,int [] in) { TreeNode root=new TreeNode(pre[0]);//前序的第一個數定為根int len=pre.length;//當只有一個數的時候if(len==1){ root.left=null; root.right=null;return root;}//找到中序中的根位置int rootval=root.val;int i;for(i=0;i<len;i++){if(rootval==in[i])break;}//建立左子樹if(i>0){int[] pr=new int[i];int[] ino=new int[i];for(int j=0;j<i;j++){pr[j]=pre[j+1];}for(int j=0;j<i;j++){ino[j]=in[j];}root.left=reConstructBinaryTree(pr,ino);}else{root.left=null;}//建立右子樹if(len-i-1>0){int[] pr=new int[len-i-1];int[] ino=new int[len-i-1];for(int j=i+1;j<len;j++){ino[j-i-1]=in[j];pr[j-i-1]=pre[j];}root.right=reConstructBinaryTree(pr,ino);}else{root.right=null;} return root; }}