剑指offer4:重建二叉树(后序遍历)

1. 题目描述

  输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

2. 思路和方法

  (1)先序遍历序列的第一个元素必定是根节点,可以由此获取二叉树的根节点。

  (2)根据根节点,中序遍历序列中查找该节点,由中序遍历的性质可知,中序遍历中该根节点左边的序列必定在根节点的左子树中,根节点右边的序列必定在右子树中。由此可以知道先序遍历中左子树以及右子树的起止位置。

  (3)分别对左子树和右子树重复上述的过程,直至所有的子树的起止位置相等时,说明已经到达叶子节点,遍历完毕。
  (4) 先序+中序->后序,中序+后序->先序,层次+中序->。

例子:

 

  先序遍历:1  2  4  5  7  8  3  6 (根左右)

  中序遍历:4  2  7  5  8  1  3  6(左根右)

  后序遍历:4  7  8  5  2  6  3  1(左右根)

  层次遍历:1  2  3  4  5  6  7  8 (共4层,与广度搜索一样,即广度遍历)

特殊例子:

先序遍历:1, 2, 4, 7, 3, 5, 6, 8 (根左右)

中序遍历:4, 7, 2, 1, 5, 3, 8, 6 (左根右)

后序遍历:7 4 2 5 8 6 3 1(左右根)

层次遍历:1 2 3 4 5 6 7 8 (共4层,与广度搜索一样,即广度遍历)

3. 核心代码

 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* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
13         int len=vin.size();
14         if (len==0)
15             return NULL;
16         vector<int> left_pre,right_pre,left_vin,right_vin;
17         TreeNode* head = new TreeNode(pre[0]);
18         int gen = 0;
19         for(int i=0;i<len;i++)
20         {
21             if(vin[i]==pre[0])
22             {
23                 gen = i;
24                 break;
25             }
26         }
27         for(int i=0;i<gen;i++)
28         {
29             left_pre.push_back(pre[i+1]);
30             left_vin.push_back(vin[i]);
31         }
32         for(int i=gen+1;i<len;i++)
33         {
34             right_pre.push_back(pre[i]);
35             right_vin.push_back(vin[i]);
36         }
37         head->left = reConstructBinaryTree(left_pre,left_vin);
38         head->right = reConstructBinaryTree(right_pre,right_vin);
39         return head;
40     }
41 };
View Code

4. C++完整实现

  1 #include <vector>
  2 #include <iostream>
  3 #include <string>
  4 #include <stdlib.h>
  5 #include <algorithm>
  6 
  7 using namespace std;
  8 
  9 struct TreeNode {
 10     int val;
 11     TreeNode *left;
 12     TreeNode *right;
 13     TreeNode(int x) :val(x), left(nullptr), right(nullptr) {}
 14 } ;
 15 
 16 //打印节点/访问函数  
 17 void PrintNode(TreeNode* T)
 18 {
 19     if (T->val != -1)
 20         cout << T->val << " ";
 21 }
 22 
 23 //先序遍历  
 24 void PreOrder(TreeNode* T)
 25 {
 26     if (T != NULL)
 27     {
 28         //访问根节点  
 29         PrintNode(T);
 30         //访问左子结点  
 31         PreOrder(T->left);
 32         //访问右子结点  
 33         PreOrder(T->right);
 34     }
 35 }
 36 
 37 //中序遍历
 38 void InOrder(TreeNode* T)
 39 {
 40     if (T != NULL)
 41     {
 42         //访问左子结点
 43         InOrder(T->left);
 44         //访问根节点
 45         PrintNode(T);
 46         //访问右子结点
 47         InOrder(T->right);
 48     }
 49 }
 50 
 51 //后序遍历
 52 void PostOrder(TreeNode* T)
 53 {
 54     if (T != NULL)
 55     {
 56         //访问左子结点
 57         PostOrder(T->left);
 58         //访问右子结点
 59         PostOrder(T->right);
 60         //访问根节点
 61         PrintNode(T);
 62     }
 63 }
 64 
 65 TreeNode* reConstructBinaryTree(vector<int> pre, vector<int> vin)
 66 {
 67     if (pre.size() == 0 || pre.size() != vin.size())
 68         return nullptr;
 69 
 70     TreeNode *newNode = new TreeNode(pre[0]);
 71     //如果只剩一个节点了,那么可以直接返回
 72     if (pre.size() == 1)
 73         return newNode;
 74 
 75     auto posi = find(vin.begin(), vin.end(), pre[0]);
 76     //错误检测
 77     if (posi == vin.end()) {
 78         return nullptr;
 79     }
 80     int leftSize = posi - vin.begin();
 81     int rightSize = vin.end() - posi - 1;
 82 
 83     //递归求解
 84     //这里取前序和后序遍历的左右子树可能有点绕,可以好好思考一下
 85     newNode->left = reConstructBinaryTree(vector<int>(pre.begin() + 1, pre.begin() + 1 + leftSize),
 86         vector<int>(vin.begin(), vin.begin() + leftSize));
 87     newNode->right = reConstructBinaryTree(vector<int>(pre.begin() + 1 + leftSize, pre.end()),
 88         vector<int>(vin.begin() + leftSize + 1, vin.end()));
 89 
 90     return newNode;
 91 }
 92 
 93 int main()
 94 {
 95     vector<int> pre{ 1, 2, 4, 7, 3, 5, 6, 8 };
 96     vector<int> vin{ 4, 7, 2, 1, 5, 3, 8, 6 }; ////7 4 2 5 8 6 3 1
 97 
 98     TreeNode *posTraversal = reConstructBinaryTree(pre, vin);
 99     
100     cout << "后序遍历:";
101     PostOrder(posTraversal);
102     cout << endl;
103 
104     cout << "先序遍历:";
105     PreOrder(posTraversal);
106     cout << endl;
107 
108     cout << "先序遍历:";
109     InOrder(posTraversal);
110     cout << endl;
111 
112     system("pause");
113     return 0;
114 }
View Code

 5 扩展

5.1 给出中序和后序,得到二叉树

后序和先序(左右根,根左右),因此后序的根的位置为pos[pos.size()-1].

main函数中的代码如下:

cout << "给出中序和后序,构建二叉树" << endl;
//vector<int> pre{ 1, 2, 4, 7, 3, 5, 6, 8 };

vector<int> vin1{ 4, 7, 2, 1, 5, 3, 8, 6 };

vector<int> pos1{ 7, 4, 2, 5, 8, 6, 3, 1 };

TreeNode* preTraversal = reConstructBinaryTree1(pos1, vin1);

cout << "中序遍历:";

InOrder(preTraversal);

cout << endl;

C++核心代码
 1 TreeNode* reConstructBinaryTree1(vector<int> pos, vector<int> vin)
 2 {
 3     if (pos.size() == 0 || pos.size() != vin.size())
 4         return nullptr;
 5 
 6     int poslen = pos.size();
 7 
 8     TreeNode *newNode = new TreeNode(pos[poslen-1]);
 9     //如果只剩一个节点了,那么可以直接返回
10     if (poslen == 1)
11         return newNode;
12 
13     auto posi = find(vin.begin(), vin.end(), pos[poslen-1]);
14     if (posi == vin.end())
15         return nullptr;
16     int leftSize = posi - vin.begin();
17     int rightSize = vin.end() - posi - 1;
18 
19     newNode->left = reConstructBinaryTree1(vector<int>(pos.begin(), pos.begin() + leftSize), vector<int>(vin.begin(), vin.begin() + leftSize));
20     newNode->right = reConstructBinaryTree1(vector<int>(pos.begin() + leftSize, pos.end()-1), vector<int>(vin.begin() + leftSize + 1, vin.end()));
21 
22     return newNode;
23 }
View Code
5.2 给出中序和层次构建二叉树

 参考资料:https://blog.csdn.net/yanyanwenmeng/article/details/77833274(一般C++程序)

 参考资料:https://blog.csdn.net/sinat_30324577/article/details/82688414(Python)

核心思想: 对于子树,其在层次遍历最前面的点即为根节点,故重建过程包括以下两步:
1.利用层次遍历确定子树的根节点;
2.根据根节点在中序中的位置划定左右子树,递归重建。

一般C++程序
 1 #include<iostream>
 2 #include<string>
 3 
 4 using namespace std;
 5 string s1, s2;
 6 void calc(int l1, int r1, int l2, int r2)
 7 {
 8     int i, j;
 9     for (i = l2; i <= r2; i++)//找层次遍历中优先输出根节点的位置 
10     {
11         int b = 0;
12         for (j = l1; j <= r1; j++)
13         {
14             if (s2[i] == s1[j])
15             {
16                 cout << s1[j];//输出根节点 
17                 b = 1;
18                 break;
19             }
20         }
21         if (b) break;
22     }
23     if (j>l1) calc(l1, j - 1, 0, r2);//遍历左子树 
24     if (j<r1) calc(j + 1, r1, 0, r2);//遍历右子树 
25 }
26 int main()
27 {
28     cin >> s1 >> s2;
29     calc(0, s1.length() - 1, 0, s2.length() - 1);
30     cout << endl;
31     return 0;
32 }
View Code

运行:输入输出

C++核心程序(vector<int>)
 1 TreeNode* reConstructBinaryTree2(vector<int> level, vector<int> vin)
 2 {
 3     if (level.size() == 0 || vin.size() == 0)
 4         return nullptr;
 5     vector<int> lst;
 6     for (int i = 0; i < vin.size(); i++){
 7         lst.push_back(find(level.begin(), level.end(), vin[i]) - level.begin());
 8     }
 9     int minPosition = min_element(lst.begin(), lst.end()) - lst.begin();
10 
11     cout << "vin[minPosition]=" << vin[minPosition] << endl;
12     TreeNode *newNode = new TreeNode(vin[minPosition]);
13 
14     newNode->left = reConstructBinaryTree2(vector<int>(level.begin(), level.end()),
15         vector<int>(vin.begin(), vin.begin() + minPosition));
16     newNode->right = reConstructBinaryTree2(vector<int>(level.begin(), level.end()),
17         vector<int>(vin.begin() + minPosition + 1, vin.end()));
18     
19     return newNode;
20
View Code

输出:

 

6. 二叉树构建参考资料:用先序构建,https://blog.csdn.net/u014453898/article/details/54894796

C++代码 
 1 #include<iostream>
 2 
 3 #include<string> 
 4 using namespace std;
 5 
 6 /*二叉树的结构体*/
 7 typedef struct BTree
 8 {
 9     int val;
10     struct BTree *left, *right;
11 }BTree;
12 
13 /*二叉树的类,包含着操作二叉树的各种方法*/
14 class Tree
15 {
16 public:
17     BTree *create_node(int level, string pos);
18     void PreOrder(BTree *t);  //先序遍历 
19     void InOrder(BTree *t);  //中序遍历 
20     void PostOrder(BTree *t);  //后序遍历 
21 
22     BTree *root;
23 };
24 
25 /*用先序遍历的方法递归构造一课二叉树*/
26 BTree* Tree::create_node(int level, string pos)
27 {
28     int data;
29     BTree *node = new BTree;
30 
31     cout << "please enter data:level " << level << " " << pos << endl;
32     cin >> data;
33 
34     //若输入的数据为0,则把该结点的子结点置为空 
35     if (data == 0)
36     {
37         return NULL;
38     }
39 
40     node->val = data;
41 
42     /*create_node()的    参数用于在给二叉树赋值时表明
43     现在赋值的是哪个结点*/
44     node->left = create_node(level + 1, "left");
45     node->right = create_node(level + 1, "right");
46     return node;
47 }
48 
49 void Tree::PreOrder(BTree *t)
50 {
51     if (t)
52     {
53         cout << t->val << endl;;
54         PreOrder(t->left);
55         PreOrder(t->right);
56     }
57 }
58 
59 void Tree::InOrder(BTree *t)
60 {
61     if (t)
62     {
63         InOrder(t->left);
64         cout << t->val << endl;;
65         InOrder(t->right);
66     }
67 }
68 
69 void Tree::PostOrder(BTree *t)
70 {
71     if (t)
72     {
73         PostOrder(t->left);
74         PostOrder(t->right);
75         cout << t->val << endl;
76     }
77 }
78 
79 int main()
80 {
81     Tree tree;
82     tree.root = tree.create_node(1, "root");
83     cout << "Pre" << endl;
84     tree.PreOrder(tree.root);
85 
86     cout << "In" << endl;
87     tree.InOrder(tree.root);
88 
89     cout << "Post" << endl;
90     tree.PostOrder(tree.root);
91 
92     system("pause");
93     return 0;
94 }
View Code

7. 完整C++程序

  1 #include <vector>
  2 #include <iostream>
  3 #include <string>
  4 #include <stdlib.h>
  5 #include <algorithm>
  6 
  7 using namespace std;
  8 
  9 struct TreeNode {
 10     int val;
 11     TreeNode *left;
 12     TreeNode *right;
 13     TreeNode(int x) :val(x), left(nullptr), right(nullptr) {}
 14 };
 15 
 16 //打印节点/访问函数  
 17 void PrintNode(TreeNode* T)
 18 {
 19     if (T->val != -1)
 20         cout << T->val << " ";
 21 }
 22 
 23 //先序遍历  
 24 void PreOrder(TreeNode* T)
 25 {
 26     if (T != NULL)
 27     {
 28         //访问根节点  
 29         PrintNode(T);
 30         //访问左子结点  
 31         PreOrder(T->left);
 32         //访问右子结点  
 33         PreOrder(T->right);
 34     }
 35 }
 36 
 37 //中序遍历
 38 void InOrder(TreeNode* T)
 39 {
 40     if (T != NULL)
 41     {
 42         //访问左子结点
 43         InOrder(T->left);
 44         //访问根节点
 45         PrintNode(T);
 46         //访问右子结点
 47         InOrder(T->right);
 48     }
 49 }
 50 
 51 //后序遍历
 52 void PostOrder(TreeNode* T)
 53 {
 54     if (T != NULL)
 55     {
 56         //访问左子结点
 57         PostOrder(T->left);
 58         //访问右子结点
 59         PostOrder(T->right);
 60         //访问根节点
 61         PrintNode(T);
 62     }
 63 }
 64 
 65 TreeNode* reConstructBinaryTree(vector<int> pre, vector<int> vin)
 66 {
 67     if (pre.size() == 0 || pre.size() != vin.size())
 68         return nullptr;
 69 
 70     TreeNode *newNode = new TreeNode(pre[0]);
 71     //如果只剩一个节点了,那么可以直接返回
 72     if (pre.size() == 1)
 73         return newNode;
 74 
 75     auto posi = find(vin.begin(), vin.end(), pre[0]);
 76 
 77     if (posi == vin.end())
 78         return nullptr;
 79     int leftSize = posi - vin.begin();
 80     int rightSize = vin.end() - posi - 1;
 81 
 82     newNode->left = reConstructBinaryTree(vector<int>(pre.begin() + 1, pre.begin() + 1 + leftSize), 
 83         vector<int>(vin.begin(), vin.begin() + leftSize));
 84     newNode->right = reConstructBinaryTree(vector<int>(pre.begin() + 1 + leftSize, pre.end()), 
 85         vector<int>(vin.begin() + leftSize + 1, vin.end()));
 86 
 87     return newNode;
 88 }
 89 
 90 
 91 TreeNode* reConstructBinaryTree1(vector<int> pos, vector<int> vin)
 92 {
 93     if (pos.size() == 0 || pos.size() != vin.size())
 94         return nullptr;
 95 
 96     int poslen = pos.size();
 97 
 98     TreeNode *newNode = new TreeNode(pos[poslen - 1]);
 99     //如果只剩一个节点了,那么可以直接返回
100     if (poslen == 1)
101         return newNode;
102 
103     auto posi = find(vin.begin(), vin.end(), pos[poslen - 1]);
104     if (posi == vin.end())
105         return nullptr;
106     int leftSize = posi - vin.begin();
107     int rightSize = vin.end() - posi - 1;
108 
109     newNode->left = reConstructBinaryTree1(vector<int>(pos.begin(), pos.begin() + leftSize), vector<int>(vin.begin(), vin.begin() + leftSize));
110     newNode->right = reConstructBinaryTree1(vector<int>(pos.begin() + leftSize, pos.end() - 1), vector<int>(vin.begin() + leftSize + 1, vin.end()));
111 
112     return newNode;
113 }
114 
115 TreeNode* reConstructBinaryTree2(vector<int> level, vector<int> vin)
116 {
117     if (level.size() == 0 || vin.size() == 0)
118         return nullptr;
119     vector<int> lst;
120     for (int i = 0; i < vin.size(); i++){
121         lst.push_back(find(level.begin(), level.end(), vin[i]) - level.begin());
122     }
123     int minPosition = min_element(lst.begin(), lst.end()) - lst.begin();
124 
125     //cout << "vin[minPosition]=" << vin[minPosition] << endl;
126     TreeNode *newNode = new TreeNode(vin[minPosition]);
127 
128     newNode->left = reConstructBinaryTree2(vector<int>(level.begin(), level.end()),
129         vector<int>(vin.begin(), vin.begin() + minPosition));
130     newNode->right = reConstructBinaryTree2(vector<int>(level.begin(), level.end()),
131         vector<int>(vin.begin() + minPosition + 1, vin.end()));
132     
133     return newNode;
134 //if not level or not vin :
135 //return None
136 //lst = []
137 //for num in vin :
138 //    lst.append(level.index(num))
139 //idx = lst.index(min(lst))
140 //
141 //root = TreeNode(vin[idx])
142 //left = vin[0:idx]
143 //right = vin[idx + 1:]
144 //root.left = restruct(level, left)
145 //root.right = restruct(level, right)
146 //return root
147 }
148 
149 
150 
151 int main()
152 {
153     //层次遍历是1 2 3 4 5 6 7 8
154     cout << "给出先序和中序,构建二叉树" << endl;
155     vector<int> pre0{ 1, 2, 4, 7, 3, 5, 6, 8 };
156     vector<int> vin0{ 4, 7, 2, 1, 5, 3, 8, 6 }; ////7 4 2 5 8 6 3 1
157 
158     TreeNode* posTraversal = reConstructBinaryTree(pre0, vin0);
159 
160     cout << "后序遍历:";
161     PostOrder(posTraversal);
162     cout << endl;
163 
164     cout << "先序遍历:";
165     PreOrder(posTraversal);
166     cout << endl;
167 
168     cout << "中序遍历:";
169     InOrder(posTraversal);
170     cout << endl;
171 
172 
173     cout << "给出中序和后序,构建二叉树" << endl;
174     //vector<int> pre{ 1, 2, 4, 7, 3, 5, 6, 8 };
175     vector<int> vin1{ 4, 7, 2, 1, 5, 3, 8, 6 };
176     vector<int> pos1{ 7, 4, 2, 5, 8, 6, 3, 1 };
177 
178     TreeNode* preTraversal = reConstructBinaryTree1(pos1, vin1);
179     cout << "后序遍历:";
180     PostOrder(preTraversal);
181     cout << endl;
182 
183     cout << "先序遍历:";
184     PreOrder(preTraversal);
185     cout << endl;
186 
187     cout << "中序遍历:";
188     InOrder(preTraversal);
189     cout << endl;
190 
191 
192     cout << "给出中序和层次,构建二叉树" << endl;
193     //vector<int> pre{ 1, 2, 4, 7, 3, 5, 6, 8 };
194     //vector<int> pos1{ 7, 4, 2, 5, 8, 6, 3, 1 };
195     vector<int> level2{ 1, 2, 3, 4, 5, 6, 7, 8 };
196     vector<int> vin2{ 4, 7, 2, 1, 5, 3, 8, 6 };
197     TreeNode* Traversal = reConstructBinaryTree2(level2, vin2);
198     cout << "后序遍历:";
199     PostOrder(Traversal);
200     cout << endl;
201 
202     cout << "先序遍历:";
203     PreOrder(Traversal);
204     cout << endl;
205 
206     cout << "中序遍历:";
207     InOrder(Traversal);
208     cout << endl;
209 
210 
211 
212     system("pause");
213     return 0;
214 }
215 
216 //class TreeNode : # 定义二叉树节点类
217 //    def __init__(self, val) :
218 //    self.val = val
219 //    self.left = None
220 //    self.right = None
221 //
222 //    def restruct(level, vin) :
223 //if not level or not vin :
224 //return None
225 //lst = []
226 //    for num in vin :
227 //    lst.append(level.index(num))
228 //        print("lst" + str(lst))
229 //        idx = lst.index(min(lst))
230 //        print("idx--" + str(idx))
231 //
232 //        root = TreeNode(vin[idx])
233 //        left = vin[0:idx]
234 //        right = vin[idx + 1:]
235 //        root.left = restruct(level, left)
236 //        root.right = restruct(level, right)
237 //        return root
238 //
239 //        lst1 = []
240 //        lst2 = []
241 //
242 //        def pre_traverse(root) :
243 //    if not root :
244 //    return None
245 //        lst1.append(root.val)
246 //        pre_traverse(root.left)
247 //        pre_traverse(root.right)
248 //        return lst1
249 //
250 //        def leaf(root) :
251 //    if not root :
252 //    return None
253 //    if not root.left and not root.right :
254 //        lst2.append(root.val)
255 //        leaf(root.left)
256 //        leaf(root.right)
257 //        return lst2
258 //
259 //        b = restruct([1, 2, 3, 4, 5, 6, 7, 8], [4, 7, 2, 1, 5, 3, 8, 6])
260 //
261 //        print(pre_traverse(b))
View Code

参考资料

https://blog.csdn.net/My_Jobs/article/details/43451187

https://blog.csdn.net/wtyvhreal/article/details/45644843

https://blog.csdn.net/m0_37950361/article/details/82531649

https://blog.csdn.net/u014453898/article/details/54894796 

https://blog.csdn.net/u014453898/article/details/54894796

https://blog.csdn.net/sinat_30324577/article/details/82688414 

转载于:https://www.cnblogs.com/wxwhnu/p/11390471.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值