[LeetCode系列] 從中序遍歷和後序遍歷序列構造二叉樹(迭代解法)

給定中序遍歷inorder和後序遍歷postorder, 請構造出二叉樹.

算法思路: 設後序遍歷爲po, 中序遍歷爲io.

 

  • 首先取出po的最後一個節點作爲根節點, 同時將這個節點入stn棧;
  • 隨後比較io的最後一個節點和stn棧頂節點:
    • 如果不同則將此節點添加到棧頂節點的右側併入stn棧, 同時從po中刪除這個節點;
      • 此時的棧中保存了所有還未處理左子樹的右側根節點
      • 出現一次不同, 右側子樹的深度就增加1, 棧的深度就代表了當前右側子樹的深度
    • 如果相同, 先緩存棧頂節點, 分別刪除io和棧頂元素:
      • 如果依舊相同(說明本層沒有左子樹), 則返回第2步;
      • 如果不同(說明有左子樹), 則將po的最後一個節點添加到緩存節點p的左側, 同時將左子樹入棧並從po中刪除此節點, 返回第2步;

代碼:

 1 /**
 2  * Definition for binary tree
 3  * struct TreeNode {
 4  *     int val;
 5  *     TreeNode *left;
 6  *     TreeNode *right;
 7  *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 8  * };
 9  */
10 class Solution {
11 public:
12     TreeNode *buildTree(vector<int> &inorder, vector<int> &postorder) {
13         if(inorder.size() == 0)return NULL;
14         TreeNode *p;
15         TreeNode *root;
16         stack<TreeNode *> stn;
17         
18         root = new TreeNode(postorder.back()); 
19         stn.push(root); 
20         postorder.pop_back(); 
21         
22         while(true)
23         {
24             if(inorder.back() == stn.top()->val) 
25             {
26                 p = stn.top();
27                 stn.pop(); 
28                 inorder.pop_back(); 
29                 if(inorder.size() == 0) break;
30                 if(stn.size() && inorder.back() == stn.top()->val)
31                     continue;
32                 p->left = new TreeNode(postorder.back()); 
33                 postorder.pop_back();
34                 stn.push(p->left);
35             }
36             else 
37             {
38                 p = new TreeNode(postorder.back());
39                 postorder.pop_back();
40                 stn.top()->right = p; 
41                 stn.push(p); 
42             }
43         }
44         return root;
45     }
46 };

中序遍歷的結果其實就是二叉樹在垂直方向的投影.

注意到中序遍歷的最後一個元素正好是二叉樹的最右端的葉子, 而後序遍歷最後才訪問根節點, 也即右側根節點都按由遠到近的順序排在最後, 所以程序第一次進入if的分支時, 樹的右側所有根節點已經構造完畢併入棧, 棧頂是最右側的根節點.

並且此時中序遍歷的結果並未刪改, 我們從下到上進行左子葉的添加:

  • 如果中序遍歷最後一個節點和棧上節點相同, 說明中序遍歷的這個節點是根節點/右側節點, 我們跳過它並從中序遍歷和棧中刪除它;
  • 但如果中序遍歷的最後一個節點不是棧上節點, 這就說明此節點是當前父節點的左子葉, 我們添加它並刪除它.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章