题目:输入某二叉树的前序遍历和中序遍历结果,重建该二叉树。(假设输入的前序和中序遍历结果中都不含重复数字)

思路

  • 构建二叉树的两个函数:Construct()、ConstructCore()
  • Construct()面向输入数据(用户),ConstructCore()面向处理数据(程序)
  • 通过Construct()调用ConstructCore(),对用户隐藏了具体实现
  1 #include "BinaryTree.h"
2 #include <stdexcept>
3 #include <iostream>
4 #include <cstdio>
5 #include <cstdlib>
6
7 BinaryTreeNode* ConstructCore(int* startPreorder, int* endPreorder, int* startInorder, int* endInorder);
8
9 BinaryTreeNode* Construct(int* preorder, int* inorder, int length)
10 {
11 if(preorder == nullptr || inorder == nullptr || length <= 0)
12 return nullptr;
13
14 return ConstructCore(preorder, preorder + length - 1,
15 inorder, inorder + length - 1);
16 }
17
18 BinaryTreeNode* ConstructCore
19 (
20 int* startPreorder, int* endPreorder,
21 int* startInorder, int* endInorder
22 )
23 {
24 // 前序遍历序列的第一个数字是根结点的值
25 int rootValue = startPreorder[0];
26 BinaryTreeNode* root = new BinaryTreeNode();
27 root->m_nValue = rootValue;
28 root->m_pLeft = root->m_pRight = nullptr;
29
30 if(startPreorder == endPreorder)
31 {
32 if(startInorder == endInorder && *startPreorder == *startInorder)
33 return root;
34 else
35 throw -1;
36 }
37
38 // 在中序遍历中找到根结点的值
39 int* rootInorder = startInorder;
40 while(rootInorder <= endInorder && *rootInorder != rootValue)
41 ++ rootInorder;
42
43 if(rootInorder == endInorder && *rootInorder != rootValue)
44 throw -1;
45
46 int leftLength = rootInorder - startInorder;
47 int* leftPreorderEnd = startPreorder + leftLength;
48 if(leftLength > 0)
49 {
50 // 构建左子树
51 root->m_pLeft = ConstructCore(startPreorder + 1, leftPreorderEnd,
52 startInorder, rootInorder - 1);
53 }
54 if(leftLength < endPreorder - startPreorder)
55 {
56 // 构建右子树
57 root->m_pRight = ConstructCore(leftPreorderEnd + 1, endPreorder,
58 rootInorder + 1, endInorder);
59 }
60
61 return root;
62 }
63
64 // ====================测试代码====================
65 void Test(char* testName, int* preorder, int* inorder, int length)
66 {
67 if(testName != nullptr)
68 printf("%s begins:\n", testName);
69
70 printf("The preorder sequence is: ");
71 for(int i = 0; i < length; ++ i)
72 printf("%d ", preorder[i]);
73 printf("\n");
74
75 printf("The inorder sequence is: ");
76 for(int i = 0; i < length; ++ i)
77 printf("%d ", inorder[i]);
78 printf("\n");
79
80 try
81 {
82 BinaryTreeNode* root = Construct(preorder, inorder, length);
83 PrintTree(root);
84 DestroyTree(root);
85 }
86 catch(int d)
87 {
88 printf("Invalid Input.\n");
89 }
90 }
91
92 // 普通二叉树
93 // 1
94 // / \
95 // 2 3
96 // / / \
97 // 4 5 6
98 // \ /
99 // 7 8
100 void Test1()
101 {
102 const int length = 8;
103 int preorder[length] = {1, 2, 4, 7, 3, 5, 6, 8};
104 int inorder[length] = {4, 7, 2, 1, 5, 3, 8, 6};
105
106 Test("Test1", preorder, inorder, length);
107 }
108
109 // 所有结点都没有右子结点
110 // 1
111 // /
112 // 2
113 // /
114 // 3
115 // /
116 // 4
117 // /
118 // 5
119 void Test2()
120 {
121 const int length = 5;
122 int preorder[length] = {1, 2, 3, 4, 5};
123 int inorder[length] = {5, 4, 3, 2, 1};
124
125 Test("Test2", preorder, inorder, length);
126 }
127
128 // 所有结点都没有左子结点
129 // 1
130 // \
131 // 2
132 // \
133 // 3
134 // \
135 // 4
136 // \
137 // 5
138 void Test3()
139 {
140 const int length = 5;
141 int preorder[length] = {1, 2, 3, 4, 5};
142 int inorder[length] = {1, 2, 3, 4, 5};
143
144 Test("Test3", preorder, inorder, length);
145 }
146
147 // 树中只有一个结点
148 void Test4()
149 {
150 const int length = 1;
151 int preorder[length] = {1};
152 int inorder[length] = {1};
153
154 Test("Test4", preorder, inorder, length);
155 }
156
157 // 完全二叉树
158 // 1
159 // / \
160 // 2 3
161 // / \ / \
162 // 4 5 6 7
163 void Test5()
164 {
165 const int length = 7;
166 int preorder[length] = {1, 2, 4, 5, 3, 6, 7};
167 int inorder[length] = {4, 2, 5, 1, 6, 3, 7};
168
169 Test("Test5", preorder, inorder, length);
170 }
171
172 // 输入空指针
173 void Test6()
174 {
175 Test("Test6", nullptr, nullptr, 0);
176 }
177
178 // 输入的两个序列不匹配
179 void Test7()
180 {
181 const int length = 7;
182 int preorder[length] = {1, 2, 4, 5, 3, 6, 7};
183 int inorder[length] = {4, 2, 8, 1, 6, 3, 7};
184 Test("Test7: for unmatched input", preorder, inorder, length);
185 }
186
187 int main(int argc, char* argv[])
188 {
189 Test1();
190 Test2();
191 Test3();
192 Test4();
193 Test5();
194 Test6();
195 Test7();
196 return 0;
197 }

             

BinaryTree.cpp

 1 #include <cstdio>
2 #include "BinaryTree.h"
3
4 BinaryTreeNode* CreateBinaryTreeNode(int value)
5 {
6 BinaryTreeNode* pNode = new BinaryTreeNode();
7 pNode->m_nValue = value;
8 pNode->m_pLeft = nullptr;
9 pNode->m_pRight = nullptr;
10
11 return pNode;
12 }
13
14 void ConnectTreeNodes(BinaryTreeNode* pParent, BinaryTreeNode* pLeft, BinaryTreeNode* pRight)
15 {
16 if(pParent != nullptr)
17 {
18 pParent->m_pLeft = pLeft;
19 pParent->m_pRight = pRight;
20 }
21 }
22
23 void PrintTreeNode(const BinaryTreeNode* pNode)
24 {
25 if(pNode != nullptr)
26 {
27 printf("value of this node is: %d\n", pNode->m_nValue);
28
29 if(pNode->m_pLeft != nullptr)
30 printf("value of its left child is: %d.\n", pNode->m_pLeft->m_nValue);
31 else
32 printf("left child is nullptr.\n");
33
34 if(pNode->m_pRight != nullptr)
35 printf("value of its right child is: %d.\n", pNode->m_pRight->m_nValue);
36 else
37 printf("right child is nullptr.\n");
38 }
39 else
40 {
41 printf("this node is nullptr.\n");
42 }
43
44 printf("\n");
45 }
46
47 void PrintTree(const BinaryTreeNode* pRoot)
48 {
49 PrintTreeNode(pRoot);
50
51 if(pRoot != nullptr)
52 {
53 if(pRoot->m_pLeft != nullptr)
54 PrintTree(pRoot->m_pLeft);
55
56 if(pRoot->m_pRight != nullptr)
57 PrintTree(pRoot->m_pRight);
58 }
59 }
60
61 void DestroyTree(BinaryTreeNode* pRoot)
62 {
63 if(pRoot != nullptr)
64 {
65 BinaryTreeNode* pLeft = pRoot->m_pLeft;
66 BinaryTreeNode* pRight = pRoot->m_pRight;
67
68 delete pRoot;
69 pRoot = nullptr;
70
71 DestroyTree(pLeft);
72 DestroyTree(pRight);
73 }
74 }

BinaryTree.h

 1 struct BinaryTreeNode
2 {
3 int m_nValue;
4 BinaryTreeNode* m_pLeft;
5 BinaryTreeNode* m_pRight;
6 };
7
8 BinaryTreeNode* CreateBinaryTreeNode(int value);
9 void ConnectTreeNodes(BinaryTreeNode* pParent, BinaryTreeNode* pLeft, BinaryTreeNode* pRight);
10 void PrintTreeNode(const BinaryTreeNode* pNode);
11 void PrintTree(const BinaryTreeNode* pRoot);
12 void DestroyTree(BinaryTreeNode* pRoot);

参考:

https://github.com/cxc1357/CodingInterviewChinese2

[刷题] 剑指Offer 面试题7:重建二叉树的更多相关文章

  1. 剑指offer面试题6 重建二叉树(c)

  2. 剑指offer面试题6 重建二叉树(java)

    注:(1)java中树的构建 (2)构建子树时可以直接利用Arrays.copyOfRange(preorder, from, to),这个方法是左开右闭的 package com.xsf.SordF ...

  3. [刷题] 剑指offer 面试题18:删除链表节点

    要求 给定单向链表的头指针和一个节点指针,在O(1)时间内删除该节点 常规思路:从头节点a开始顺序遍历,发现p指向要删除的节点i,然后把p的m_pNext指向i的下一个节点j,时间复杂度O(n) O( ...

  4. 剑指Offer:面试题6——重建二叉树(java实现)

    问题描述:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不包含重复的数字. 例如: 输入:前序{1,2,4,7,3,5,6,8},中序{4,7,2,1 ...

  5. C++版 - 剑指Offer 面试题39:二叉树的深度(高度)(二叉树深度优先遍历dfs的应用) 题解

    剑指Offer 面试题39:二叉树的深度(高度) 题目:输入一棵二叉树的根结点,求该树的深度.从根结点到叶结点依次经过的结点(含根.叶结点)形成树的一条路径,最长路径的长度为树的深度.例如:输入二叉树 ...

  6. 剑指Offer - 九度1385 - 重建二叉树

    剑指Offer - 九度1385 - 重建二叉树2013-11-23 23:53 题目描述: 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的 ...

  7. 剑指offer_面试题6_重建二叉树(分解步骤,逐个击破)

    题目:输入某二叉树的前序遍历和中序遍历的结果.请重建出该二叉树.如果输入的前序遍历和中序遍历的结果中都不含反复的数字. 比如:输入前序遍历 {1,2,4,7,3,5,6,8} 和中序遍历序列 {4,7 ...

  8. 剑指offer——面试题8:二叉树的下一个节点

    // 面试题8:二叉树的下一个结点 // 题目:给定一棵二叉树和其中的一个结点,如何找出中序遍历顺序的下一个结点? // 树中的结点除了有两个分别指向左右子结点的指针以外,还有一个指向父结点的指针. ...

  9. 剑指offer(4)重建二叉树

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

随机推荐

  1. 第26 章 : 理解 CNI 和 CNI 插件

    理解 CNI 和 CNI 插件 本文将主要分享以下几方面的内容: CNI 是什么? Kubernetes 中如何使用 CNI? 哪个 CNI 插件适合我? 如何开发自己的 CNI 插件? CNI 是什 ...

  2. CyclicBarrier:人齐了,老司机就可以发车了!

    上一篇咱讲了 CountDownLatch 可以解决多个线程同步的问题,相比于 join 来说它的应用范围更广,不仅可以应用在线程上,还可以应用在线程池上.然而 CountDownLatch 却是一次 ...

  3. 2-fabric网络搭建流程

    目录 一.示例网络 下面开始一步步的搭建和叙述上述过程 二.创建网络 三.添加网络管理员 四.定义联盟 五.为联盟创建通道 六.节点和账本 七.应用程序和智能合约链码 八.完成网络 简化视觉词汇表 九 ...

  4. MySQL实战45讲,丁奇带你搞懂

    之前,你大概都是通过搜索别人的经验来解决问题.如果能够理解MySQL的工作原理,那么在遇到问题的时候,是不是就能更快地直戳问题的本质? 以实战中的常见问题为切入点,带你剖析现象背后的本质原因.为你串起 ...

  5. 动态的创建Class对象方法及调用方式性能分析

    有了Class对象,能做什么? 创建类的对象:调用Class对象的newInstance()方法 类必须有一个无参数的构造器. 类的构造器的访问权限需要足够. 思考?没有无参的构造器就不能创建对象吗? ...

  6. 简述Java多线程(二)

    Java多线程(二) 线程优先级 Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程,线程调度器按照优先级决定应该调度哪个线程来执行. 优先级高的不一定先执行,大多数情况是这样的. 优 ...

  7. ES6 第二天

    三点运算符 <script type="text/javascript"> function func(...params){ params.forEach(funct ...

  8. Kubernetes 普及系列:容器基础入门

    随着云原生时代的来临,云以及分布式计算已经是时下最受欢迎的技术之一了.其中 Docker 作为最知名的容器平台,到底有着怎样的魅力来让其无人不知无人不晓?废话不多说,让我们开始逐层掀开容器技术的神秘面 ...

  9. 【软件工程】《构建之法》 & Git+ & CI/CD

    <构建之法> & Git+ & CI/CD 个人阅读作业#2 项目 内容 本作业所属课程 2020春季软件工程(罗杰 任健) 本作业要求 个人阅读作业#2 我的课程目标 具 ...

  10. &#127822;

    江湖中有一本练了就能天下无敌的葵花宝典,大家都想得到它.如果有一天葵花宝典被公开了,人人都有机会练,到底是好事还是坏事呢? 这会成为一个灾难. 因为一个人拥有时,练不练是一个人的事.大家都拥有,练不练 ...