@@ -3,25 +3,27 @@ https://leetcode-cn.com/problems/binary-tree-preorder-traversal/
33
44## 思路
55
6- 这篇文章,彻底讲清楚应该如何写递归,并给出了前中后序三种不同的迭代法,最后分析为什么迭代法代码风格不能统一 ,最后给出统一的前中后序迭代法的代码,帮大家彻底吃透二叉树的深度优先遍历。
6+ 这篇文章,** 彻底讲清楚应该如何写递归,并给出了前中后序三种不同的迭代法,然后分析迭代法的代码风格为什么没有统一 ,最后给出统一的前中后序迭代法的代码,帮大家彻底吃透二叉树的深度优先遍历。**
77
8- 这里想帮大家一下,明确一下二叉树的遍历规则
98
109* 二叉树深度优先遍历
11- * 前序遍历: 144 .二叉树的前序遍历
12- * 后序遍历: 145 .二叉树的后序遍历
13- * 中序遍历: 094 .二叉树的中序遍历
10+ * 前序遍历: [ 0144 .二叉树的前序遍历] ( https://github.com/youngyangyang04/leetcode/blob/master/problems/0144.二叉树的前序遍历.md )
11+ * 后序遍历: [ 0145 .二叉树的后序遍历] ( https://github.com/youngyangyang04/leetcode/blob/master/problems/0145.二叉树的后序遍历.md )
12+ * 中序遍历: [ 0094 .二叉树的中序遍历] ( https://github.com/youngyangyang04/leetcode/blob/master/problems/0094.二叉树的中序遍历.md )
1413* 二叉树广度优先遍历
15- * 层序遍历:0145.二叉树的后序遍历
14+ * 层序遍历:[ 0102.二叉树的层序遍历 ] ( https://github.com/youngyangyang04/leetcode/blob/master/problems/0102.二叉树的层序遍历.md )
1615
17- 这几道题目建议大家都做一下,本题解先只写二叉树深度优先遍历,二叉树广度优先遍历请看[ 0102.二叉树的层序遍历] ( https://github.com/youngyangyang04/leetcode/blob/master/problems/0102.二叉树的层序遍历.md )
16+ 这几道题目建议大家都做一下,本题解先只写二叉树深度优先遍历,二叉树广度优先遍历请看题解[ 0102.二叉树的层序遍历] ( https://github.com/youngyangyang04/leetcode/blob/master/problems/0102.二叉树的层序遍历.md )
17+
18+ 这里想帮大家一下,明确一下二叉树的遍历规则:
1819
1920![ 二叉树前后中遍历] ( https://img-blog.csdnimg.cn/20200808191505393.png )
2021
21- 以上述中,前中后序遍历顺序如下
22- 前序遍历(中左右):5 4 1 2 6 7 8
23- 中序遍历(左中右):1 4 2 5 7 6 8
24- 后序遍历(左右中):1 2 4 7 8 6 5
22+ 以上述中,前中后序遍历顺序如下:
23+
24+ * 前序遍历(中左右):5 4 1 2 6 7 8
25+ * 中序遍历(左中右):1 4 2 5 7 6 8
26+ * 后序遍历(左右中):1 2 4 7 8 6 5
2527
2628### 递归法
2729
@@ -31,15 +33,11 @@ https://leetcode-cn.com/problems/binary-tree-preorder-traversal/
3133
3234
33351 . ** 确定递归函数的参数和返回值:**
34-
3536确定哪些参数是递归的过程中需要处理的,那么就在递归函数里加上这个参数, 并且还要明确每次递归的返回值是什么进而确定递归函数的返回类型。
3637
37-
38382 . ** 确定终止条件:**
39-
4039写完了递归算法, 运行的时候,经常会遇到栈溢出的错误,就是没写终止条件或者终止条件写的不对,操作系统也是用一个栈的结构来保存每一层递归的信息,如果递归没有终止,操作系统的内存栈必然就会溢出。
4140
42-
43413 . ** 确定单层递归的逻辑:**
4442确定每一层递归需要处理的信息。在这里也就会重复调用自己来实现递归的过程。
4543
@@ -67,11 +65,9 @@ traversal(cur->left, vec); // 左
6765traversal(cur->right, vec); // 右
6866```
6967
70- 单层递归的逻辑就是按照中左右的顺序来处理的
68+ 单层递归的逻辑就是按照中左右的顺序来处理的,这样二叉树的前序遍历,基本就写完了,在看一下完整代码:
7169
72- 这样二叉树的前序遍历,基本就写完了,在看一下完整代码:
73-
74- 前序遍历
70+ 前序遍历:
7571
7672```
7773class Solution {
@@ -90,7 +86,7 @@ public:
9086};
9187```
9288
93- 中序遍历
89+ 中序遍历:
9490
9591```
9692 void traversal(TreeNode* cur, vector<int>& vec) {
@@ -101,7 +97,7 @@ public:
10197 }
10298```
10399
104- 后序遍历
100+ 后序遍历:
105101
106102```
107103 void traversal(TreeNode* cur, vector<int>& vec) {
@@ -119,6 +115,7 @@ public:
119115那么接下来我先带大家看一看其中的根本原因,其实是可以针对三种遍历方式,使用迭代法可以写出统一风格的代码。
120116
121117前序遍历(迭代法)不难写出如下代码:
118+
122119```
123120class Solution {
124121public:
@@ -141,7 +138,7 @@ public:
141138
142139这时会发现貌似使用迭代法写出先序遍历并不难,确实不难,但难却难在,我们再用迭代法写中序遍历的时候,发现套路又不一样了,目前的这个逻辑无法直接应用到中序遍历上。
143140
144- #### 为什么迭代法不容易写出统一风格的代码
141+ #### 前后中遍历迭代法不统一的写法
145142
146143为了解释清楚,我说明一下 刚刚在迭代的过程中,其实我们有两个操作,** 一个是处理:将元素放进result数组中,一个是访问:遍历节点。**
147144
@@ -206,15 +203,15 @@ public:
206203
207204```
208205
209- 此时我们实现了前后中遍历的三种迭代法,是不是发现迭代法实现的先中后序,其实风格也不是那么统一,除了先序和后序,有关联,中序完全就是另一个风格了,一会用栈遍历,一会又用指针来遍历。
206+ 此时我们实现了前后中遍历的三种迭代法,** 是不是发现迭代法实现的先中后序,其实风格也不是那么统一,除了先序和后序,有关联,中序完全就是另一个风格了,一会用栈遍历,一会又用指针来遍历。**
210207
211- 重头戏来了,接下来介绍一下统一写法。
208+ ** 重头戏来了,接下来介绍一下统一写法。**
212209
213- #### 迭代法统一写法
210+ #### 前后中遍历迭代法统一的写法
214211
215212我们以中序遍历为例,之前说使用栈的话,** 无法同时解决处理过程和访问过程不一致的情况** ,那我们就将访问的节点放入栈中,把要处理的节点也放入栈中但是要做标记,标记就是要处理的节点放入栈之后,紧接着放入一个空指针作为标记。
216213
217- 代码如下 :
214+ 中序遍历代码如下 :
218215```
219216class Solution {
220217public:
@@ -248,12 +245,66 @@ public:
248245
249246<video src =' ../video/中序遍历迭代(统一写法).mp4 ' controls =' controls ' width =' 640 ' height =' 320 ' autoplay =' autoplay ' > Your browser does not support the video tag.</video ></div >
250247
248+ 前序遍历代码如下:
249+
250+ ```
251+ class Solution {
252+ public:
253+ vector<int> preorderTraversal(TreeNode* root) {
254+ vector<int> result;
255+ stack<TreeNode*> st;
256+ if (root != NULL) st.push(root);
257+ while (!st.empty()) {
258+ TreeNode* node = st.top();
259+ if (node != NULL) {
260+ st.pop();
261+ if (node->right) st.push(node->right); // 右
262+ if (node->left) st.push(node->left); // 左
263+ st.push(node); // 中
264+ st.push(NULL);
265+ } else {
266+ st.pop();
267+ node = st.top();
268+ st.pop();
269+ result.push_back(node->val);
270+ }
271+ }
272+ return result;
273+ }
274+ };
275+ ```
276+
277+ 后续遍历代码如下:
251278
252- 大家在看一下具体代码实现
279+ ```
280+ class Solution {
281+ public:
282+ vector<int> postorderTraversal(TreeNode* root) {
283+ vector<int> result;
284+ stack<TreeNode*> st;
285+ if (root != NULL) st.push(root);
286+ while (!st.empty()) {
287+ TreeNode* node = st.top();
288+ if (node != NULL) {
289+ st.pop();
290+ st.push(node); // 中
291+ st.push(NULL);
292+
293+ if (node->right) st.push(node->right); // 右
294+ if (node->left) st.push(node->left); // 左
253295
254- 接下来给大家介绍一种统一的写法。
296+ } else {
297+ st.pop();
298+ node = st.top();
299+ st.pop();
300+ result.push_back(node->val);
301+ }
302+ }
303+ return result;
304+ }
305+ };
306+ ```
255307
256- 我们再来看一下代码。
257308## C++代码
258309
259310### 递归
@@ -296,7 +347,7 @@ public:
296347```
297348
298349### 栈 通用模板
299- 详细代码注释看 [ 0094.二叉树的中序遍历 ] ( https://github.com/youngyangyang04/leetcode/blob/master/problems/0094.二叉树的中序遍历.md )
350+
300351```
301352class Solution {
302353public:
@@ -308,9 +359,9 @@ public:
308359 TreeNode* node = st.top();
309360 if (node != NULL) {
310361 st.pop();
311- if (node->right) st.push(node->right);
312- if (node->left) st.push(node->left);
313- st.push(node);
362+ if (node->right) st.push(node->right); // 右
363+ if (node->left) st.push(node->left); // 左
364+ st.push(node); // 中
314365 st.push(NULL);
315366 } else {
316367 st.pop();
0 commit comments