1010
1111** 扩展**
1212
13- - 多叉树的遍历,参考[ 图的遍历] ( https://github.com/suukii/Articles/blob/master/articles/dsa_graph.md )
14- - O(1)空间的遍历,[ Morris Traversal] ( https://github.com/suukii/Articles/blob/master/articles/dsa_binary_tree.md#morris-traversal )
13+ - 多叉树的遍历,参考[ 图的遍历] ( https://github.com/suukii/Articles/blob/master/articles/dsa/ dsa_graph.md#%E5%9B%BE%E7%9A%84%E9%81%8D%E5%8E%86 )
14+ - $ O(1)$ 空间的遍历,[ Morris Traversal] ( https://github.com/suukii/Articles/blob/master/articles/dsa /dsa_binary_tree.md#morris-traversal )
1515
1616# 144.二叉树的前序遍历
1717
@@ -33,8 +33,8 @@ preorder(root.right)
3333
3434### 复杂度分析
3535
36- - 时间复杂度:O(2^h),h 为二叉树的高度。也可以表示为 O(n),n 为二叉树的节点数。
37- - 空间复杂度:O(h),h 为二叉树的高度。
36+ - 时间复杂度:$ O(2^h)$ ,h 为二叉树的高度。也可以表示为 $ O(n)$ ,n 为二叉树的节点数。
37+ - 空间复杂度:$ O(h)$ ,h 为二叉树的高度。
3838
3939### 代码
4040
@@ -53,13 +53,13 @@ JavaScript Code
5353 * @return {number[]}
5454 */
5555var preorderTraversal = function (root , res = []) {
56- if (! root) return []
56+ if (! root) return [];
5757
58- res .push (root .val )
59- root .left && preorderTraversal (root .left , res)
60- root .right && preorderTraversal (root .right , res)
61- return res
62- }
58+ res .push (root .val );
59+ root .left && preorderTraversal (root .left , res);
60+ root .right && preorderTraversal (root .right , res);
61+ return res;
62+ };
6363```
6464
6565## 迭代
@@ -87,18 +87,18 @@ JavaScript Code
8787 * @return {number[]}
8888 */
8989var preorderTraversal = function (root ) {
90- const stack = [root]
91- const res = []
92-
93- while (stack .length > 0 ) {
94- const node = stack .pop ()
95- if (node) {
96- res .push (node .val )
97- stack .push (node .right , node .left )
90+ const stack = [root];
91+ const res = [];
92+
93+ while (stack .length > 0 ) {
94+ const node = stack .pop ();
95+ if (node) {
96+ res .push (node .val );
97+ stack .push (node .right , node .left );
98+ }
9899 }
99- }
100- return res
101- }
100+ return res;
101+ };
102102```
103103
104104# 94.二叉树的中序遍历
@@ -136,12 +136,12 @@ JavaScript Code
136136 * @return {number[]}
137137 */
138138var inorderTraversal = function (root , res = []) {
139- if (! root) return []
140- root .left && inorderTraversal (root .left , res)
141- res .push (root .val )
142- root .right && inorderTraversal (root .right , res)
143- return res
144- }
139+ if (! root) return [];
140+ root .left && inorderTraversal (root .left , res);
141+ res .push (root .val );
142+ root .right && inorderTraversal (root .right , res);
143+ return res;
144+ };
145145```
146146
147147## 迭代
@@ -170,20 +170,20 @@ JavaScript Code
170170 * @return {number[]}
171171 */
172172var inorderTraversal = function (root ) {
173- const stack = []
174- const res = []
175-
176- while (root || stack .length > 0 ) {
177- while (root) {
178- stack .push (root)
179- root = root .left
173+ const stack = [];
174+ const res = [];
175+
176+ while (root || stack .length > 0 ) {
177+ while (root) {
178+ stack .push (root);
179+ root = root .left ;
180+ }
181+ root = stack .pop ();
182+ res .push (root .val );
183+ root = root .right ;
180184 }
181- root = stack .pop ()
182- res .push (root .val )
183- root = root .right
184- }
185- return res
186- }
185+ return res;
186+ };
187187```
188188
189189# 145.二叉树的后序遍历
@@ -221,24 +221,28 @@ JavaScript Code
221221 * @return {number[]}
222222 */
223223var postorderTraversal = function (root , res = []) {
224- if (! root) return []
225- root .left && postorderTraversal (root .left , res)
226- root .right && postorderTraversal (root .right , res)
227- res .push (root .val )
228- return res
229- }
224+ if (! root) return [];
225+
226+ root .left && postorderTraversal (root .left , res);
227+ root .right && postorderTraversal (root .right , res);
228+ res .push (root .val );
229+
230+ return res;
231+ };
230232```
231233
232234## 迭代
233235
234- ### 思路
236+ ### 思路 1
237+
238+ 这是比较讨巧的思路。
235239
2362401 . 二叉树的前序遍历是 root -> left -> right
2372412 . 二叉树的后序遍历是 left -> right -> root
2382423 . 可以看到后序遍历差不多是前序遍历的结果倒转过来,我们可以把前序遍历的套路拿过来稍做改动。
2392434 . 只需把第 2 步把 node 存入 res 这一步由 ` res.push(node.val) ` 改为 ` res.unshift(node.val) ` ,并且将左右子节点入栈的顺序调换一下即可。
240244
241- ### 代码
245+ ### 代码 1
242246
243247JavaScript Code
244248
@@ -255,17 +259,79 @@ JavaScript Code
255259 * @return {number[]}
256260 */
257261var postorderTraversal = function (root ) {
258- const stack = [root]
259- const res = []
260- while (stack .length > 0 ) {
261- const node = stack .pop ()
262- if (node) {
263- stack .push (node .left , node .right )
264- res .unshift (node .val )
262+ const stack = [root];
263+ const res = [];
264+ while (stack .length > 0 ) {
265+ const node = stack .pop ();
266+ if (node) {
267+ stack .push (node .left , node .right );
268+ res .unshift (node .val );
269+ }
265270 }
266- }
267- return res
268- }
271+ return res;
272+ };
273+ ```
274+
275+ ### 思路 2
276+
277+ 这是比较正经的思路。
278+
279+ 因为后序遍历的顺序是 left -> right -> root,我们需要先遍历 left,但如果直接遍历,访问完 left 之后没办法回到 root 了,因为二叉树的子节点是没有指向父节点的指针的。
280+
281+ 所以,在遍历 left 之前,我们需要把 root 和 right 存起来,访问完 left 之后再回到 root,这时候需要判断,如果 root.right 存在且还没访问过,就先去访问 root.right,否则直接打印 root 的值。
282+
283+ 1 . 将 root.right 和 root 入栈,稍后遍历。
284+ 2 . 让 ` root = root.left ` (相当于将 root 看成一个 cur 指针)。
285+ 3 . 当 root 不为空时,重复步骤 1 和 2。
286+ 4 . 开始出栈,` root = stack.pop() ` ,检查 root.right 有没有被访问过:
287+ 1 . 如果没有被访问过的话,这时候 root.right 应该在栈顶,将 root.right 弹出,然后将 root 压回栈等最后再遍历。接着让 ` root = root.right ` ,开始处理右子树。
288+ 2 . 如果已经被访问过,或者 root.right 为空的话,这时我们直接打印 root 的值就好了。
289+
290+ ### 代码 2
291+
292+ JavaScript Code
293+
294+ ``` js
295+ /**
296+ * Definition for a binary tree node.
297+ * function TreeNode(val) {
298+ * this.val = val;
299+ * this.left = this.right = null;
300+ * }
301+ */
302+ /**
303+ * @param {TreeNode} root
304+ * @return {number[]}
305+ */
306+ var postorderTraversal = function (root ) {
307+ if (! root) return [];
308+
309+ const stack = [];
310+ const res = [];
311+
312+ while (true ) {
313+ while (root) {
314+ root .right && stack .push (root .right );
315+ stack .push (root);
316+ root = root .left ;
317+ }
318+
319+ root = stack .pop ();
320+
321+ if (root .right && root .right === stack[stack .length - 1 ]) {
322+ const right = stack .pop ();
323+ stack .push (root);
324+ root = right;
325+ } else {
326+ res .push (root .val );
327+ root = null ;
328+ }
329+
330+ if (! stack .length ) break ;
331+ }
332+
333+ return res;
334+ };
269335```
270336
271337# 102.二叉树的层序遍历
@@ -288,8 +354,8 @@ var postorderTraversal = function (root) {
288354
289355### 复杂度分析
290356
291- - 时间复杂度:O(n),n 为树的节点数。
292- - 空间复杂度:O(2^h),h 为树的高度,队列的最大长度是最深一层叶子节点的总数 2^(h-1)。
357+ - 时间复杂度:$ O(n)$ ,n 为树的节点数。
358+ - 空间复杂度:$ O(2^h)$ ,h 为树的高度,队列的最大长度是最深一层叶子节点的总数 $ 2^(h-1)$ 。
293359
294360### 代码
295361
@@ -309,27 +375,27 @@ JavaScript Code
309375 * @return {number[][]}
310376 */
311377var levelOrder = function (root ) {
312- if (! root) return []
313-
314- const result = []
315- const queue = [root, null ]
316- let level = 0
317-
318- while (queue .length > 0 ) {
319- const node = queue .shift ()
320-
321- if (node) {
322- result[level] || (result[level] = [])
323- result[level].push (node .val )
324- node .left && queue .push (node .left )
325- node .right && queue .push (node .right )
326- } else {
327- queue .length > 0 && queue .push (null )
328- level++
378+ if (! root) return [];
379+
380+ const result = [];
381+ const queue = [root, null ];
382+ let level = 0 ;
383+
384+ while (queue .length > 0 ) {
385+ const node = queue .shift ();
386+
387+ if (node) {
388+ result[level] || (result[level] = []);
389+ result[level].push (node .val );
390+ node .left && queue .push (node .left );
391+ node .right && queue .push (node .right );
392+ } else {
393+ queue .length > 0 && queue .push (null );
394+ level++ ;
395+ }
329396 }
330- }
331- return result
332- }
397+ return result;
398+ };
333399```
334400
335401Python Code
@@ -356,12 +422,15 @@ class Solution(object):
356422 while len (queue) > 0 :
357423 size = len (queue)
358424 level = []
425+
359426 for i in range (size):
360427 node = queue.pop(0 )
428+
361429 if node != None :
362430 level.append(node.val)
363431 if node.left != None : queue.append(node.left)
364432 if node.right != None : queue.append(node.right)
433+
365434 items.append(level)
366435 return items
367436```
@@ -374,8 +443,8 @@ class Solution(object):
374443
375444### 复杂度分析
376445
377- - 时间复杂度:O(n), n 为二叉树的节点数。
378- - 空间复杂度:O(n), n 为二叉树的节点数,` res ` 数组的空间是 O(n),调用栈的空间最大是 O(h),h 是二叉树的深度,因为 n >= h,所以最后还是 O(n)。
446+ - 时间复杂度:$ O(n)$ , n 为二叉树的节点数。
447+ - 空间复杂度:$ O(n)$ , n 为二叉树的节点数,` res ` 数组的空间是 $ O(n)$ ,调用栈的空间最大是 $ O(h)$ ,h 是二叉树的深度,因为 $ n >= h$ ,所以最后还是 $ O(n)$ 。
379448
380449### 代码
381450
@@ -394,12 +463,14 @@ JavaScript Code
394463 * @return {number[][]}
395464 */
396465var levelOrder = function (root , depth = 0 , res = []) {
397- if (! root) return []
398-
399- res[depth] || (res[depth] = [])
400- res[depth].push (root .val )
401- levelOrder (root .left , depth + 1 , res)
402- levelOrder (root .right , depth + 1 , res)
403- return res
404- }
466+ if (! root) return [];
467+
468+ res[depth] || (res[depth] = []);
469+ res[depth].push (root .val );
470+
471+ levelOrder (root .left , depth + 1 , res);
472+ levelOrder (root .right , depth + 1 , res);
473+
474+ return res;
475+ };
405476```
0 commit comments