一、分清前、中、后序遍历
看根节点遍历的顺序,左子节点一定在右子节点之前遍历 :
- 前序 : 根左右
- 中序 : 左根右
- 后序 : 左右根
二、前序遍历
递归写法 : 直接看代码 :
迭代算法 :
众所周知,把递归改成迭代就需要手动去维护一个栈,关键就在于理清栈的入栈出栈顺序。首先我们一定要搞清楚一点,栈是先进慢出的,因此我们要先遍历左子节点,就要先把右子节点入栈。
由于前序遍历的顺序是:根左右。当我们出栈时,得到的元素就是一个根节点 (记为node),这时候我们可以对根节点进行处理。然后我们再把node的右子节点和左子节点分别入栈,这样等到出栈的时候就是先出左子节点、再出右子节点,符合前序遍历的顺序。
当理不清出入栈顺序时,手动画一个栈模拟一下就能清楚。
三、中序遍历
递归写法:与前序遍历的写法类似,这里就不写了。
迭代写法:
(1) 前序遍历时,访问的第一个节点就是我们要处理的第一个节点,而中序遍历不一样,我们访问的第一个节点 (根节点)并不是我们要处理的第一个节点 (最左的节点)。事实上,我们访问到的每一个节点都是中间节点。因此,在处理节点之前我们需要先找到这个“最左”的节点,这需要一次循环,不断向左走,边走边把遇到的节点都入栈。
(2)在我们进行出栈操作时,也就是root = myStack.offerLast();这条代码时候,root左子节点代表的这棵树已经完全遍历完了,这时候我们要做的就是对中间节点root进行处理,然后赋值root = root.right,目的是在下次循环的时候完成右子节点代表的这棵树的遍历。
(3) 最外层循环的循环条件:①首先,root!=null这点跟递归写法的意义类似。② !myStack.isEmpty(),栈非空代表还有一些节点没被遍历到。
(4) 与递归写法联系一下:
参考资料:https://leetcode-cn.com/problems/binary-tree-inorder-traversal/solution/dai-ma-sui-xiang-lu-che-di-chi-tou-qian-xjof1/
四、后序遍历
递归写法:与前序遍历的写法类似,这里就不写了。
迭代写法:
这里注意一下红色框圈出来的这句话,因为后序遍历的顺序是:左右根。因此当处理完根节点之后,需要把root置null,这样下次进来循环的时候才会从栈中弹出节点;否则就会继续向左搜索,陷入死循环。
参考资料:https://leetcode-cn.com/problems/binary-tree-postorder-traversal/solution/er-cha-shu-de-hou-xu-bian-li-by-leetcode-solution/