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 };
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 }
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 }
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 }
运行:输入输出
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 }
输出:
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 }
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))
参考资料
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