|
| 1 | +我们之前说了二叉树基础及二叉的几种遍历方式及练习题,今天我们来看一下二叉树的前序遍历非递归实现。 |
| 2 | + |
| 3 | +前序遍历的顺序是, 对于树中的某节点,`先遍历该节点,然后再遍历其左子树,最后遍历其右子树`. |
| 4 | + |
| 5 | +我们先来通过下面这个动画复习一下二叉树的前序遍历。 |
| 6 | + |
| 7 | + |
| 8 | + |
| 9 | +### 迭代 |
| 10 | + |
| 11 | +我们试想一下,之前我们借助队列帮我们实现二叉树的层序遍历, |
| 12 | + |
| 13 | +那么可不可以,也借助数据结构,帮助我们实现二叉树的前序遍历。 |
| 14 | + |
| 15 | +见下图 |
| 16 | + |
| 17 | + |
| 18 | + |
| 19 | +假设我们的二叉树为 [1,2,3]。我们需要对其进行前序遍历。其遍历顺序为 |
| 20 | + |
| 21 | +当前节点 1,左孩子 2,右孩子 3。 |
| 22 | + |
| 23 | +这里可不可以用栈,帮我们完成前序遍历呢? |
| 24 | + |
| 25 | +> 栈和队列的那些事 |
| 26 | +
|
| 27 | +我们都知道栈的特性是先进后出,我们借助栈来帮助我们完成前序遍历的时候。 |
| 28 | + |
| 29 | +则需要注意的一点是,我们应该先将右子节点入栈,再将左子节点入栈。 |
| 30 | + |
| 31 | +这样出栈时,则会先出左节点,再出右子节点,则能够完成树的前序遍历。 |
| 32 | + |
| 33 | +见下图。 |
| 34 | + |
| 35 | + |
| 36 | + |
| 37 | +我们用一句话对上图进行总结,当栈不为空时,栈顶元素出栈,如果其右孩子不为空,则右孩子入栈,其左孩子不为空,则左孩子入栈。还有一点需要注意的是,我们和层序遍历一样,需要先将 root 节点进行入栈,然后再执行 while 循环。 |
| 38 | + |
| 39 | +看到这里你已经能够自己编写出代码了,不信你去试试。 |
| 40 | + |
| 41 | +时间复杂度:O(n) 需要对所有节点遍历一次 |
| 42 | + |
| 43 | +空间复杂度:O(n) 栈的开销,平均为 O(logn) 最快情况,即斜二叉树时为 O(n) |
| 44 | + |
| 45 | +**参考代码** |
| 46 | + |
| 47 | +```java |
| 48 | +class Solution { |
| 49 | + public List<Integer> preorderTraversal(TreeNode root) { |
| 50 | + List<Integer> list = new ArrayList<>(); |
| 51 | + Stack<TreeNode> stack = new Stack<>(); |
| 52 | + if (root == null) return list; |
| 53 | + stack.push(root); |
| 54 | + while (!stack.isEmpty()) { |
| 55 | + TreeNode temp = stack.pop(); |
| 56 | + if (temp.right != null) { |
| 57 | + stack.push(temp.right); |
| 58 | + } |
| 59 | + if (temp.left != null) { |
| 60 | + stack.push(temp.left); |
| 61 | + } |
| 62 | + //这里也可以放到前面 |
| 63 | + list.add(temp.val); |
| 64 | + } |
| 65 | + return list; |
| 66 | + } |
| 67 | +} |
| 68 | +``` |
| 69 | + |
| 70 | +### Morris |
| 71 | + |
| 72 | +Morris 遍历利用树的左右孩子为空(大量空闲指针),实现空间开销的极限缩减。这个遍历方法,稍微难理解一些,不过结合动图,也就一目了然啦,各位系好安全带,我们要发车啦。 |
| 73 | + |
| 74 | + |
| 75 | + |
0 commit comments