1.题目描述:
给你一棵二叉树的根节点root,返回其节点值的后序遍历。
2.递归后序遍历:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
private List<Integer> list = new ArrayList<>();
public List<Integer> postorderTraversal(TreeNode root) {
postOrder(root);
return list;
}
public void postOrder(TreeNode root) {
if (root == null) return;
postOrder(root.left);
postOrder(root.right);
list.add(root.val);
}
}
3.使用栈的迭代后序遍历(借助前序遍历):
参考leetcode144. 二叉树的前序遍历,借助栈遍历顺序为root—>left—>right,修改原代码遍历顺序为root—>right—>left,后序遍历为left—>right—>root,需要再将list集合反转。但逻辑上来说,这不算严格意义的后序遍历,只不过把list集合反转了。
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while (!stack.isEmpty()) {
TreeNode temp = stack.pop();
if (temp == null) continue;
list.add(temp.val);//这种方法永远是root节点的val先存入
stack.push(temp.left);
//list.add(temp.val);写在这里效果一样
stack.push(temp.right);
//list.add(temp.val);写在这里效果一样
}
Collections.reverse(list);
return list;
}
}
更加容易理解的写法:
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
if (root == null) return list;//防止后续的空指针
stack.push(root);
while (!stack.isEmpty()) {
TreeNode temp = stack.pop();
list.add(temp.val);
if (temp.left != null) stack.push(temp.left);
if (temp.right != null) stack.push(temp.right);//中、右、左
}
Collections.reverse(list);//左、右、中
return list;
}
}
4.使用栈的迭代后序遍历:
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> list = new LinkedList<>();
Stack<TreeNode> stack = new Stack<>();
TreeNode prev=null;
//由于在某颗子树访问完成以后,接着就要回溯到其父节点去
//因此可以用prev来记录访问历史,回溯到父节点时由此来判断上一个访问的节点是否为右子树
while(root != null || !stack.isEmpty()){
while(root != null){
stack.push(root);
root = root.left;
}
//从栈中弹出的元素,左子树是访问到底的
root = stack.pop();
//确定是否有右子树,或者右子树是否访问过(上一个访问的节点是右子节点)
if(root.right == null || prev == root.right){
ans.add(root.val);
//更新访问记录,回溯时父节点可由此判断右子树是否访问完成
prev = root;
root = null;
}else{
//若右子树没有被访问,将当前节点压入栈并访问右子树
stack.push(root);
root = root.right;
}
}
return ans;
}
}
5.Morris遍历:
与Morris前序和中序遍历不同,麻烦一点,待补充。