1.文字描述:
已知一顆二叉樹的前序(后序)遍歷序列和中序遍歷序列,如何構建這棵二叉樹?
以前序為例子:
前序遍歷序列:ABCDEF
中序遍歷序列:CBDAEF
前序遍歷先訪問根節點,因此前序遍歷序列的第一個字母肯定就是根節點,即A是根節點;然后,由於中序遍歷先訪問左子樹,再訪問根節點,最后訪問右子樹,所以我們找到中序遍歷中A的位置,然后A左邊的字母就是左子樹了,也就是CBD是根節點的左子樹;同樣的,得到EF為根節點的右子樹。
將前序遍歷序列分成BCD和EF,分別對左子樹和右子樹應用同樣的方法,遞歸下去,二叉樹就成功構建好了。如下圖:
假如已知的是中序和后序遍歷的序列,原理也一樣。由於后序是先訪問左子樹,然后訪問右子樹,最后訪問根節點,因此我們確定后序遍歷序列的最后一個字母為根節點。其他步驟一樣,用中序遍歷序列找出兩棵子樹,再進行同樣的操作。
2.代碼實現:
(1)已知前序和中序:
Leetcode題目:
105 Construct Binary Tree from Preorder and Inorder Traversal(https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/description/)
代碼:
class Solution { public: TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) { return buildTree(preorder, inorder, 0, preorder.size() - 1, 0, inorder.size() - 1); } TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder, int preStart, int preEnd, int inStart, int inEnd) { if (preStart > preEnd || inStart > inEnd) return NULL; TreeNode *res; res = new TreeNode(preorder[preStart]); int flag; for (int i = inStart; i <= inEnd; i++) { if (preorder[preStart] == inorder[i]) { flag = i; break; } } res->left = buildTree(preorder, inorder, preStart + 1, preStart + flag - inStart, inStart, flag - 1); res->right = buildTree(preorder, inorder, preStart + flag - inStart + 1, preEnd, flag + 1, inEnd); return res; } };
一開始我采用的做法是遇到的每棵子樹都用新的vector數組來存放它的中序和前序遍歷序列,但這樣又浪費空間又增加時間,我們只要用原來的vector數組就可以了。
因此我們要用preStart,preEnd,inStart和inEnd來保存序列開始和結束的位置。比較容易得出的是inStart和inEnd這兩個位置;難理解的是左子樹的preEnd和右子樹的preStart。但是我們求出左子樹的preEnd后,只要加1就是右子樹的preStart了。而要求左子樹的preEnd我們可以通過中序來求出左子樹的元素個數,然后就可以求出這個位置了。
(1)已知中序和后序:
Leetcode題目:
106 Construct Binary Tree from Inorder and Postorder Traversal(https://leetcode.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/description/)
代碼:
class Solution { public: TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) { return buildTree(inorder, postorder, 0, inorder.size() - 1, postorder.size() - 1, 0); } TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder, int inStart, int inEnd, int postEnd, int postStart) { if (inStart > inEnd || postEnd < postStart) { return NULL; } int flag; TreeNode *res = new TreeNode(postorder[postEnd]); for (int i = inStart; i <= inEnd; i++) { if (inorder[i] == postorder[postEnd]) { flag = i; break; } } res->left = buildTree(inorder, postorder, inStart, flag - 1, postStart - inStart + flag - 1, postStart); res->right = buildTree(inorder, postorder, flag + 1, inEnd, postEnd - 1, postEnd - inEnd + flag); return res; } };