树的三种遍历方式
中序遍历Leetcode94
刷完的题目回头看总是不会做,特此总结
当根节点遍历完成的时候,需要根节点进行中转到右子树
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
public class Solution {
public static void main(String[] args) {
TreeNode t1 = new TreeNode(1);
TreeNode t2 = new TreeNode(2);
TreeNode t3 = new TreeNode(3);
t1.left = null;
t1.right = t2;
t2.left = t3;
t2.right = null;
t3.left = null;
t3.right = null;
List<Integer> ans = new Solution().inorderTraversal(t1);
System.out.println(ans);
}
public List<Integer> inorderTraversal(TreeNode root) {
ArrayDeque<TreeNode> stack = new ArrayDeque<>();
ArrayList<Integer> list = new ArrayList<>();
if(root == null)
return list;
//注意终结条件的设定,画图分析会比较清晰,添加了root!=null的条件才能进入循环或者转移到右子树
while(!stack.isEmpty() || root != null){
while(root != null){
stack.push(root);
root = root.left;
}
root = stack.pop();
list.add(root.val);
//左子树已经遍历完成或者为空,右子树不为空则转移到右子树
root = root.right;
}
return list;
}
}
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) {
val = x;
}
}
前序遍历Leetcode144
初始将根节点入栈,后面的流程:弹栈输出->右节点压入栈中->左节点压入栈中。通过反序压入栈中达到弹出的顺序为根->左->右
public List<Integer> preorderTraversal(TreeNode root) {
ArrayDeque<TreeNode> stack = new ArrayDeque<>();
ArrayList<Integer> list = new ArrayList<>();
if(root == null)
return list;
stack.push(root);
while(!stack.isEmpty()){
TreeNode t = stack.pop();
list.add(t.val);
//先压入右节点,再压入左节点,这样弹栈遍历的顺序就是中左右
if(t.right != null)
stack.push(t.right);
if(t.left != null)
stack.push(t.left);
}
return list;
}
后序遍历Leetcode145
下面的解法和中序遍历类似,只是后续遍历在转移到右子树的时候不能将根节点弹出,也即通过左子树访问根节点的时候根节点不能弹出,通过右节点访问根节点的时候说明左右子树都已经访问过了,可以弹出。通过set存储节点来确定是第一次访问还是第二次访问,已经访问过的节点存储在set中
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
public class Solution {
public static void main(String[] args) {
TreeNode t1 = new TreeNode(3);
TreeNode t2 = new TreeNode(1);
TreeNode t3 = new TreeNode(2);
t1.left = t2;
t1.right = t3;
t2.left = null;
t2.right = null;
t3.left = null;
t3.right = null;
Solution solution = new Solution();
List<Integer> ans = solution.postorderTraversal(t1);
System.out.println(ans);
}
public List<Integer> postorderTraversal(TreeNode root) {
ArrayDeque<TreeNode> stack = new ArrayDeque<>();
ArrayList<Integer> list = new ArrayList<>();
HashSet<TreeNode> set = new HashSet<>();
while(!stack.isEmpty() || root != null){
while(root != null){
stack.push(root);
root = root.left;
}
//不直接弹出,查看栈顶的右节点进行判断
//ArrayDeque的peek是查看栈顶,jdk8的中文文档似乎有误
root = stack.peek();
if(set.contains(root) || root.right == null){
//栈顶弹出,如果为空就可以结束了,root设置为null防止循环回到上面的语句时继续插入重复节点
root = stack.pop();
list.add(root.val);
root = null;
} else {
//因为是后序遍历,不能直接弹出栈顶进行转移
//添加进set表示访问过,转到右子树
set.add(root);
root = root.right;
}
}
return list;
}
}
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;
}
}