題目:輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二叉樹


  

  

  問題描述:

    輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重復的數字。例如輸入前序遍歷序列{1,2,4,7,3,5,6,8}和中序遍歷序列{4,7,2,1,5,3,8,6},則重建二叉樹並返回。

  思路:

  在二叉樹的前序遍歷序列中,第一個數字總是樹的根結點的值。但在中序遍歷序列中,根結點的值在序列的中間,左子樹的結點的值位於根結點的值的左邊,而右子樹的結點的值位於根結點的值的右邊。因此我們需要掃描中序遍歷序列,才能找到根結點的值。

  如下圖所示,前序遍歷序列的第一個數字1就是根結點的值。掃描中序遍歷序列,就能確定根結點的值的位置。根據中序遍歷特點,在根結點的值1前面的3個數字都是左子樹結點的值,位於1后面的數字都是右子樹結點的值。

 

 

  

  同樣,在前序遍歷的序列中,根結點后面的3個數字就是3個左子樹結點的值,再后面的所有數字都是右子樹結點的值。這樣我們就在前序遍歷和中序遍歷兩個序列中,分別找到了左右子樹對應的子序列。

  既然我們已經分別找到了左、右子樹的前序遍歷序列和中序遍歷序列,我們可以用同樣的方法分別去構建左右子樹。也就是說,接下來的事情可以用遞歸的方法去完成。
  完整的代碼示例如下,方式一使用數組存儲前序遍歷序列和中序遍歷序列;方式二使用容器存儲。

  1 /*
  2 題目描述
  3 輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重復的數字。
  4 例如輸入前序遍歷序列{1,2,4,7,3,5,6,8}和中序遍歷序列{4,7,2,1,5,3,8,6},則重建二叉樹並返回。
  5 */
  6 
  7 /*
  8 思路:
  9 先序遍歷的第一個元素為根節點,在中序遍歷中找到這個根節點,從而可以將中序遍歷分為左右兩個部分,
 10 左邊部分為左子樹的中序遍歷,右邊部分為右子樹的中序遍歷,進而也可以將先序遍歷除第一個元素以外的剩余部分分為兩個部分,
 11 第一個部分為左子樹的先序遍歷,第二個部分為右子樹的先序遍歷。
 12 由上述分析結果,可以遞歸調用構建函數,根據左子樹、右子樹的先序、中序遍歷重建左、右子樹。
 13 */
 14 /*
 15 Time:2016年9月9日11:57:07
 16 Author:CodingMengmeng
 17 */
 18 
 19 /*
 20 方式一:
 21     數組+遞歸
 22 */
 23 #include <iostream>
 24 using namespace std;
 25 
 26 //樹結點結構體
 27 struct BinaryTreeNode
 28 {
 29 
 30     int                    m_nValue;
 31     BinaryTreeNode*        m_pLeft;
 32     BinaryTreeNode*        m_pRight;
 33 
 34 
 35 
 36 };
 37 
 38 //打印樹結點
 39 void PrintTreeNode(BinaryTreeNode *pNode)
 40 {
 41     if (pNode != NULL)
 42     {
 43         printf("value of this node is : %d\n", pNode->m_nValue);
 44 
 45         if (pNode->m_pLeft != NULL)
 46             printf("value of its left child is: %d.\n", pNode->m_pLeft->m_nValue);
 47         else
 48             printf("left child is null.\n");
 49         if (pNode->m_pRight != NULL)
 50             printf("value of its right childe is : %d.\n", pNode->m_pRight->m_nValue);
 51         else
 52             printf("right child is null.\n");
 53     }
 54     else
 55     {
 56 
 57         printf("this node is null.\n");
 58 
 59     }
 60     printf("\n");
 61 }
 62 void PrintTree(BinaryTreeNode *pRoot)
 63 {
 64     PrintTreeNode(pRoot);
 65     //   
 66     if (pRoot != NULL)
 67     {
 68         if (pRoot->m_pLeft != NULL)
 69             PrintTree(pRoot->m_pLeft);
 70         if (pRoot->m_pRight != NULL)
 71             PrintTree(pRoot->m_pRight);
 72     }
 73 }
 74 
 75 /*
 76 preorder 前序遍歷
 77 inorder 中序遍歷
 78 
 79 */
 80 
 81 BinaryTreeNode* ConstructCore(int* startPreorder, int* endPreorder, int* startInorder, int* endInorder);
 82 BinaryTreeNode *Construct(int *preorder, int *inorder, int length)//輸入前序序列,中序序列和序列長度
 83 {
 84     if (preorder == NULL || inorder == NULL || length <= 0)
 85         return NULL;
 86     return ConstructCore(preorder, preorder + length - 1, inorder, inorder + length - 1);
 87 
 88 }
 89 
 90 // startPreorder 前序遍歷的第一個節點  
 91 // endPreorder   前序遍歷的最后后一個節點  
 92 // startInorder  中序遍歷的第一個節點  
 93 // startInorder  中序遍歷的最后一個節點  
 94 
 95 BinaryTreeNode* ConstructCore(int* startPreorder, int* endPreorder, int* startInorder, int* endInorder)
 96 {
 97     // 前序遍歷序列的第一個數字是根結點的值  
 98     int rootValue = startPreorder[0];
 99     BinaryTreeNode *root = new BinaryTreeNode();
100     root->m_nValue = rootValue;
101     root->m_pLeft = root->m_pRight = NULL;
102     
103     // 只有一個結點
104     if (startPreorder == endPreorder)
105     {
106         if (startInorder == endInorder && *startPreorder == *startInorder)
107             return root;
108         else
109             throw std::exception("Invalid input.");
110     }
111 
112     //有多個結點
113     // 在中序遍歷中找到根結點的值  
114     int *rootInorder = startInorder;
115     while (rootInorder <= endInorder && *rootInorder != rootValue)
116         ++rootInorder;
117     if (rootInorder == endInorder && *rootInorder != rootValue)
118         throw std::exception("Invalid input");
119     //  
120     int leftLength = rootInorder - startInorder;    //中序序列的左子樹序列長度
121     int *leftPreorderEnd = startPreorder + leftLength;    //左子樹前序序列的最后一個結點
122     if (leftLength > 0)
123     {
124         // 構建左子樹  
125         root->m_pLeft = ConstructCore(startPreorder + 1, leftPreorderEnd, startInorder, rootInorder - 1);
126     }
127     if (leftLength < endPreorder - startPreorder)    //(中序序列)若還有左子樹,則左子樹序列長度應等於當前前序序列的長度
128         //若小於,說明已無左子樹,此時建立右子樹
129     {
130         // 構建右子樹  
131         root->m_pRight = ConstructCore(leftPreorderEnd + 1, endPreorder, rootInorder + 1, endInorder);
132     }
133     //  
134     return root;
135 }
136 
137 // 測試代碼  
138 void Test(char *testName, int *preorder, int *inorder, int length)
139 {
140     if (testName != NULL)
141         printf("%s Begins:\n", testName);
142     printf("The preorder sequence is: ");
143     for (int i = 0; i < length; ++i)
144         printf("%d ", preorder[i]);
145     printf("\n");
146 
147     printf("The inorder sequence is:");
148     for (int i = 0; i < length; ++i)
149         printf("%d ", inorder[i]);
150     printf("\n");
151 
152     try
153     {
154         BinaryTreeNode *root = Construct(preorder, inorder, length);
155         PrintTree(root);
156 
157     }
158     catch (std::exception &expection)
159     {
160         printf("Invalid Input.\n");
161     }
162 }
163 
164 // 普通二叉樹  
165 //              1  
166 //           /     \  
167 //          2       3    
168 //         /       / \  
169 //        4       5   6  
170 //         \         /  
171 //          7       8  
172 void Test1()
173 {
174     const int length = 8;
175     int preorder[length] = { 1, 2, 4, 7, 3, 5, 6, 8 };
176     int inorder[length] = { 4, 7, 2, 1, 5, 3, 8, 6 };
177 
178     Test("Test1", preorder, inorder, length);
179 }
180 
181 int main()
182 {
183     Test1();  
184     system("pause");
185     return 0;
186 }
187 
188 /*
189 輸出結果:
190 ----------------------------------------------------------------
191 Test1 Begins:
192 The preorder sequence is: 1 2 4 7 3 5 6 8
193 The inorder sequence is:4 7 2 1 5 3 8 6
194 value of this node is : 1
195 value of its left child is: 2.
196 value of its right childe is : 3.
197 
198 value of this node is : 2
199 value of its left child is: 4.
200 right child is null.
201 
202 value of this node is : 4
203 left child is null.
204 value of its right childe is : 7.
205 
206 value of this node is : 7
207 left child is null.
208 right child is null.
209 
210 value of this node is : 3
211 value of its left child is: 5.
212 value of its right childe is : 6.
213 
214 value of this node is : 5
215 left child is null.
216 right child is null.
217 
218 value of this node is : 6
219 value of its left child is: 8.
220 right child is null.
221 
222 value of this node is : 8
223 left child is null.
224 right child is null.
225 
226 請按任意鍵繼續. . .
227 ----------------------------------------------------------------
228 
229 */
230 
231 /*
232 方式二:容器+遞歸
233 */
234 
235 #include <iostream>
236 #include <vector>
237 using namespace std;
238 
239 
240 // Definition for binary tree
241 struct TreeNode {
242      int val;
243      TreeNode *left;
244      TreeNode *right;
245      TreeNode(int x) : val(x), left(NULL), right(NULL) {}
246  };
247 
248 /* 先序遍歷第一個位置肯定是根節點node,
249 
250 中序遍歷的根節點位置在中間p,在p左邊的肯定是node的左子樹的中序數組,p右邊的肯定是node的右子樹的中序數組
251 
252 另一方面,先序遍歷的第二個位置到p,也是node左子樹的先序子數組,剩下p右邊的就是node的右子樹的先序子數組
253 
254 把四個數組找出來,分左右遞歸調用即可
255 
256 */
257 
258 class Solution {
259 
260 public:
261 
262     struct TreeNode* reConstructBinaryTree(vector<int> pre, vector<int> in) {
263 
264         int in_size = in.size();//獲得序列的長度
265 
266         if (in_size == 0)
267 
268             return NULL;
269 
270         //分別存儲先序序列的左子樹,先序序列的右子樹,中序序列的左子樹,中序序列的右子樹
271         vector<int> pre_left, pre_right, in_left, in_right;
272 
273         int val = pre[0];//先序遍歷第一個位置肯定是根節點node,取其值
274         //新建一個樹結點,並傳入結點值
275         TreeNode* node = new TreeNode(val);//root node is the first element in pre
276         //p用於存儲中序序列中根結點的位置
277         int p = 0;
278 
279         for (p; p < in_size; ++p){
280 
281             if (in[p] == val) //Find the root position in in 
282 
283                 break;        //找到即跳出for循環
284 
285         }
286 
287         for (int i = 0; i < in_size; ++i){
288 
289             if (i < p){
290                 //建立中序序列的左子樹和前序序列的左子樹
291                 in_left.push_back(in[i]);//Construct the left pre and in 
292 
293                 pre_left.push_back(pre[i + 1]);//前序第一個為根節點,+1從下一個開始記錄
294 
295             }
296 
297             else if (i > p){
298                 //建立中序序列的右子樹和前序序列的左子樹
299                 in_right.push_back(in[i]);//Construct the right pre and in 
300 
301                 pre_right.push_back(pre[i]);
302 
303             }
304 
305         }
306         //取出前序和中序遍歷根節點左邊和右邊的子樹
307         //遞歸,再對其進行上述所有步驟,即再區分子樹的左、右子子數,直到葉節點
308         node->left = reConstructBinaryTree(pre_left, in_left);
309 
310         node->right = reConstructBinaryTree(pre_right, in_right);
311 
312         return node;
313 
314     }
315 
316 };

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM