二叉树的preorder, inorder and postorder 遍历,在leetcode中都有对应的题。下面一起介绍,同时介绍recursion和iteration两种方式实现。
https://leetcode.com/problems/binary-tree-inorder-traversal/
https://leetcode.com/problems/binary-tree-preorder-traversal/
https://leetcode.com/problems/binary-tree-postorder-traversal/
首先看中序遍历,最简单的是递归实现,很好理解,下面是实现代码(这一套实现可以作为前序、中序、后序遍历的模板):
// 中序遍历
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
inorderHelper(root, res);
return res;
}
private void inorderHelper(TreeNode root, List res) {
if (root != null) {
if (root.left != null) inorderHelper(root.left, res);
res.add(root.val);
if (root.right != null) inorderHelper(root.right, res);
}
}
相应的,作为对比,给出前序和后序遍历的实现:
// 前序遍历
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
preorderHelper(root, res);
return res;
}
private void preorderHelper(TreeNode root, List res) {
if (root != null) {
res.add(root.val);
if (root.left != null) preorderHelper(root.left, res);
if (root.right != null) preorderHelper(root.right, res);
}
}
后序遍历:
// 后序遍历
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
postorderHelper(root, res);
return res;
}
private void postorderHelper(TreeNode root, List res) {
if (root != null) {
if (root.left != null) postorderHelper(root.left, res);
if (root.right != null) postorderHelper(root.right, res);
res.add(root.val);
}
}
如果使用iteration遍历,三种访问方式都可以采用stack实现。可以对比着看,具体实现看代码注释。
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>(); // 返回结果
Stack<TreeNode> stack = new Stack<>();
TreeNode curr = root;
pushItselfAndAllLeft(curr, stack); // 将自己和它的所有左节点全部入栈
while(!stack.isEmpty()) {
TreeNode tmp = stack.pop(); // 出栈,最晚进的最先出
res.add(tmp.val);
if (tmp.right != null) pushItselfAndAllLeft(tmp.right, stack); // 访问一次右子树的自生和全部左节点
}
return res;
}
private void pushItselfAndAllLeft(TreeNode curr, Stack<TreeNode> stack) {
while (curr != null) {
stack.push(curr);
curr = curr.left;
}
}
前序遍历:
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>(); // 返回结果
if (root == null) return res; // 防止将null值push到stack中
Stack<TreeNode> stack = new Stack<>();
TreeNode curr = root;
stack.push(curr); // push 根节点
while(!stack.isEmpty()) {
TreeNode tmp = stack.pop();
res.add(tmp.val);
if (tmp.right != null) stack.push(tmp.right); // 因为栈具有后入先出的特性,所以先push右子树
if (tmp.left != null) stack.push(tmp.left);
}
return res;
}
后序遍历则稍微复杂一点,主要是涉及到一个reverse操作,具体可以看实现中的注释:
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>(); // 返回结果
if (root == null) return res; // 防止将null值push到stack中
Stack<TreeNode> stack = new Stack<>();
TreeNode curr = root;
stack.push(curr); // push 根节点
while(!stack.isEmpty()) {
TreeNode tmp = stack.pop();
// 后续遍历顺序是左,右,顶点,所以此时插入的时候都插到最前面,相当于reverse.
// 可以理解为遍历 顶点、右、左,得到的结果再reverse
res.add(0, tmp.val);
if (tmp.left != null) stack.push(tmp.left); // 因为栈具有后入先出的特性,所以先push右子树
if (tmp.right != null) stack.push(tmp.right);
}
return res;
}