輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二叉樹。假設輸入的前序序列和中序序列的結果都不含重復的數字,例如輸入前序序列{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,所以對於遞歸還得加強學習啊!!!
如果理解了遞歸的訪問,那么建樹的過程就容易多了,前序遍歷序列的第一個數(后序遍歷的最后一個數)一定是根結點,所以可以根據此結點在中序序列中的位置把中序序列分為左子樹和右子數兩個部分,同樣的道理,在左子樹和右子數中同樣可以用到這樣的規律來確定每個中間結點。
1 #include<iostream> 2 using namespace std; 3 struct BinaryTreeNode 4 { 5 int m_value; 6 BinaryTreeNode *p_left; 7 BinaryTreeNode *p_right; 8 }; 9 BinaryTreeNode* ConstructCore(int *startPreorder, int *endPreorder, int *startInorder, int *endInorder)//前序序列的開始、結束指針和中序序列的開始結束指針 10 { 11 int rootValue = startPreorder[0];//前序序列的第一個值必然是根結點 12 BinaryTreeNode* root = new BinaryTreeNode(); 13 root->m_value = rootValue; 14 root->p_left = nullptr; 15 root->p_right = nullptr; 16 if (startPreorder == endPreorder){ 17 if (startInorder == endInorder&&*startPreorder == *startInorder)//只有一個數字 18 return root; 19 else 20 throw exception("Invalid input"); 21 } 22 int* rootInorder = startInorder;//在中序序列中找到根節點的位置 23 while (rootInorder <= endInorder&& *rootInorder != rootValue) 24 ++rootInorder; 25 if (rootInorder == endInorder&&*rootInorder != rootValue) 26 throw exception("Invalid Input"); 27 int leftLength = rootInorder - startInorder;//左子樹序列長度 28 int* leftPreorderEnd = startPreorder + leftLength;//左子樹前序序列的最后一個結點 29 if (leftLength > 0)//建立左子樹 30 { 31 root->p_left = ConstructCore(startPreorder + 1, leftPreorderEnd, startInorder, rootInorder-1); 32 } 33 if (leftLength < endPreorder - startPreorder)//建立右子樹 34 { 35 root->p_right = ConstructCore(leftPreorderEnd + 1, endPreorder, rootInorder + 1, endInorder); 36 } 37 return root; 38 } 39 BinaryTreeNode* Construt(int *preorder, int *inorder, int length)//輸入前序序列,中序序列和序列長度 40 { 41 if (preorder == nullptr || inorder == nullptr || length <= 0) 42 return nullptr; 43 return ConstructCore(preorder, preorder + length - 1, inorder, inorder + length - 1); 44 }