先序遍历
分析:
采用栈的方式实现。二叉树最左侧的一排是最先需要入栈的,然后先令最左侧的最下面的一个节点出栈,它是第一个被遍历的元素,然后查询它是否存在右子节点,如果存在右子节点,则需要把从右子节点出发的一系列左子树入栈,再用和上述同样的方式操作。关键是把节点存入list的时机,这里是在入栈的时候存,因为优先遍历根节点。
代码:
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
while (!stack.isEmpty() || root != null) {
while (root != null) {
res.add(root.val);
stack.push(root);
root = root.left;
}
root = stack.pop();
root = root.right;
}
return res;
}
中序遍历
分析:
中序遍历不能一开始就存,需要在弹栈的时候存,因为它需要确保最先访问的是左子节点,当这个节点弹栈并存值的时候,接下来就开始遍历其右子节点了。和先序遍历的区别就是在list中添加节点的时机不同。
代码:
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
while (!stack.isEmpty() || root != null) {
while (root != null) {
stack.push(root);
root = root.left;
}
root = stack.pop();
res.add(root.val);
root = root.right;
}
return res;
}
后序遍历
分析:
后序遍历的思路稍有技巧性,它的顺序是左、右、根,假设对它做一反转,为根、右、左。如果考虑这种类先序遍历可以更快得到结果,接下来对先序遍历做一修改,先从右侧开始寻找,再往左侧。关于反转的实现,只要将list中每一个数据插入到队列的最前侧即可。
代码:
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
while (!stack.isEmpty() || root != null) {
while (root != null) {
res.add(0, root.val);
stack.push(root);
root = root.right;
}
root = stack.pop();
root = root.left;
}
return res;
}