前序遍历和中序遍历
通过指针指向树的各个节点,不为空则放入栈,等待后续遍历,指针每次遍历左边节点,再遍历右边节点。
相当于
1
2 3
4 5 6 7
执行
// 结点栈:
null
// 第一次弹出,加入到结点栈
1
// 加入到结果集
1
// p 指向左结点
p = 2
// 以此类推
// 结点栈
4 5 2 1
// 结果集
1 2 4 5
// p 指向空
这时候,弹出4
p 指向5
// 以此遍历
public List<Integer> preorderTraversal(TreeNode root) {
Deque<TreeNode> stack = new ArrayDeque<>();
List<Integer> resList = new ArrayList<>();
TreeNode p = root;
while (!stack.isEmpty() || p != null) {
if (p != null) {
stack.push(p);
resList.add(p.val);
p = p.left;
} else {
TreeNode tmp = stack.pop();
p = tmp.right;
}
}
return resList;
}
中序遍历
public List<Integer> preorderTraversal(TreeNode root) {
Deque<TreeNode> stack = new ArrayDeque<>();
List<Integer> resList = new ArrayList<>();
TreeNode p = root;
while (!stack.isEmpty() || p != null) {
if (p != null) {
stack.push(p);
p = p.left;
} else {
TreeNode tmp = stack.pop();
resList.add(tmp.val);
p = tmp.right;
}
}
return resList;
}
后序遍历
我个人理解的有两种方法
-
层次遍历(力扣官方题解)
每次把栈首元素弹出放入结果集,按元素的右左孩子的顺序压入栈,之后再弹出。
比如
1 2 3 4 5 6 7
那么我们第一次压栈的顺序是
// 开始时结点栈顺序 1 // 结点栈顺序(弹出1加入到结果) 3 2 // 结果栈的顺序 1 // 第二次结点栈顺序(弹出3加入到结果) 7 6 2 // 第二次结果栈顺序 3 1 // 以此类推。。。 // 右结点遍历完的结点栈 2 // 结果栈 6 7 3 1 // 再类推就可以得到结果
public List<Integer> postorderTraversal(TreeNode root) { if (root == null) { return new ArrayList<>(0); } Deque<TreeNode> stack = new ArrayDeque<>(); Deque<Integer> deque = new LinkedList<>(); stack.push(root); TreeNode p = null; while (!stack.isEmpty()) { p = stack.pop(); deque.push(p.val); if (p.left != null) { stack.push(p.left); } if (p.right != null) { stack.push(p.right); } } return (List<Integer>) deque; }
-
压栈模仿递归,每次压右再压左,这样左边遍历完就可以直接遍历右边了。直到走到空,例如:
1 2 3 4 5 6 7
栈中是这样的
4 5 2 3 1
这个时候,直接把4加入到结果集就可以,然后再看一下下一个5,4和5没有关系,所以直接遍历5。
接下来是这样的,由于5左右都没有结点,所以到了需要弹出5的时候了,这个时候,先弹出5,加到结果集,然后再取出第一个2,看5和2的关系,是父子关系,证明2已经遍历过了,直接把2弹出就行了。
5 2 3 1
最后结果可能是这样的
7 3 1
这个时候就需要弹出一次,再看下一个是不是也是父子关系,相当于连续弹出三次,完毕。
public List<Integer> postorderTraversal2(TreeNode root) { if (root == null) { return new ArrayList<>(); } Deque<TreeNode> stack = new ArrayDeque<>(); List<Integer> resList = new ArrayList<>(); stack.push(root); TreeNode p = root; while (!stack.isEmpty()) { if (p != null) { if (p.right != null) stack.push(p.right); if (p.left != null) stack.push(p.left); p = p.left != null ? p.left : p.right; } else { TreeNode tmp = stack.pop(); resList.add(tmp.val); TreeNode pre = stack.peek(); while (isChildren(tmp, pre)) { resList.add(pre.val); tmp = stack.pop(); pre = stack.peek(); } p = pre; } } return resList; } private boolean isChildren(TreeNode c, TreeNode p) { if (c == null || p == null) { return false; } return p.left == c || p.right == c; }