题目:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树

 

  

  问题描述:

    输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{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 };
时间: 2024-10-10 23:59:23

题目:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树的相关文章

输入某二叉树的前序遍历和中序遍历的结果,重建出该二叉树

//================================================================== // <剑指Offer--名企面试官精讲典型编程题>代码 // 作者:何海涛 //================================================================== // 面试题7:重建二叉树 // 题目:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输 // 入的前序遍历和中序遍历的结果中都

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

问题描述: 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回. 思路: 在二叉树的前序遍历序列中,第一个数字总是树的根结点的值.但在中序遍历序列中,根结点的值在序列的中间,左子树的结点的值位于根结点的值的左边,而右子树的结点的值位于根结点的值的右边.因此我们需要扫描中序遍历序列,才能找到根结点的值. 如下图所示,

根据二叉树的前序遍历和中序遍历重建二叉树

题目描述 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回. 1 /** 2 * Definition for binary tree 3 * struct TreeNode { 4 * int val; 5 * TreeNode *left; 6 * TreeNode *right; 7 * TreeNode(

027依据前序遍历和中序遍历,重建二叉树(keep it up)

剑指offer中题目:http://ac.jobdu.com/problem.php?pid=1385 题目描写叙述: 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.如果输入的前序遍历和中序遍历的结果中都不含反复的数字. 比如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并输出它的后序遍历序列. 输入: 输入可能包括多个測试例子,对于每一个測试案例, 输入的第一行为一个整数n(1<=n<=1000):代表二叉树的节点

N4-某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。

题目描述 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回. //本题思路参考另一个大神写的代码 其原地址为:https://www.nowcoder.com/profile/566744/codeBookDetail?submissionId=1516321 /** * 输入某二叉树的前序遍历和中序遍历的结果,

二叉树 根据二叉树的前序数组和中序序遍历数组生成二叉树

题目:给定二叉树的前序遍历和中序遍历,生成二叉树. Example: 前序遍历数组:preArr[]:{1,2,4,5,3,6,7} 中序遍历数组:inArr[]:{4,2,5,1,6,3,7} 生成的二叉树如下图: 解题思路: 由二叉树的前序变量性质可知:preArr[0] 是数组的根节点,有根据二叉树的中序遍历的性质可知,{4,2,5}是二叉树的左子树,{6,3,7}在右子树上,重复执行该操作就构造出了二叉树 public class Solution { public TreeNode r

二叉树、前序遍历、中序遍历、后序遍历

一.树 在谈二叉树前先谈下树和图的概念 树:不包含回路的连通无向图(树是一种简单的非线性结构) 树有着不包含回路这个特点,所以树就被赋予了很多特性 1.一棵树中任意两个结点有且仅有唯一的一条路径连通 2.一棵树如果有n个结点,那它一定恰好有n-1条边 3.在一棵树中加一条边将会构成一个回路 4.树中有且仅有一个没有前驱的结点称为根结点 在对树进行讨论的时候将树中的每个点称为结点, 根结点:没有父结点的结点 叶结点:没有子结点的结点 内部结点:一个结点既不是根结点也不是叶结点 每个结点还有深度,比

已知二叉树的前序遍历、中序遍历或者中序遍历、后序遍历求二叉树结构的算法

二叉树中的前序遍历是先访问根结点,再访问左子树,右子树. 中序遍历是先访问左子树,再是根结点,最后是右子树. 后序遍历是先访问左子树,再是右子树,最后是根结点. 算法思路是先根据前序遍历的第一个结点或者后序遍历的最后一个结点,查找对应在中序遍历中的位置,就可以确定左子树包含的元素和右子树包含的元素,最后通过递归来实现就可以了. 二叉树的表示形式为 //二叉树的结构表示为 class TreeNode { int val; TreeNode left; TreeNode right; TreeNo

前序遍历和中序遍历重建二叉树

对于二叉树,在此我不做过多讲解,如有不懂,请参照一下链接点击打开链接 1.在此二叉树的定义: struct BinaryTreeNode     {         BinaryTreeNode<T> *_Left;         BinaryTreeNode<T> *_Right;         T _data;     public:         BinaryTreeNode(const T& x)             :_Left(NULL)