对于深度优先,每种遍历顺序均用 递归法 和 迭代法 实现(难点在于后者)
最后是层序遍历
节点的定义先写在前面
LeetCode会提供,但建议自己会写
/**
* 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 {
// public List<Integer> preorderTraversal(TreeNode root) {
// List<Integer> result = new ArrayList<>();
// preOrder(root, result);
// return result;
// }
// private void preOrder(TreeNode root, List<Integer> result){
// if(root==null){
// return;
// }
// result.add(root.val);// 不同遍历方式只在于本行代码放在哪里
// preOrder(root.left,result);
// preOrder(root.right,result);
// }
// }
//迭代法(前序遍历还是比较简单的)
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
// 如果树空就不用处理了
if(root==null){
return result;
}
// 树不空的情况
Deque<TreeNode> stack = new LinkedList<>();
stack.offerFirst(root);
while(!stack.isEmpty()){
TreeNode node = stack.pollFirst();
result.add(node.val);
// 因为前序遍历是 中 左 右,
// 所以用栈模拟的话,要先压入右节点,这样左节点才会先出栈
if(node.right!=null){
stack.offerFirst(node.right);
}
if(node.left!=null){
stack.offerFirst(node.left);
}
}
return result;
}
}
中序遍历
//递归法
// class Solution {
// public List<Integer> inorderTraversal(TreeNode root) {
// List<Integer> result = new ArrayList<>();
// inOrder(root,result);
// return result;
// }
// private void inOrder(TreeNode root, List<Integer> result){
// if(root==null){
// return;
// }
// inOrder(root.left, result);
// result.add(root.val);
// inOrder(root.right, result);
// }
// }
//迭代法(稍微有点难但问题不大)
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
if(root==null){
return result;
}
Deque<TreeNode> stack = new LinkedList<>();
TreeNode cur = root;
while(cur!=null || !stack.isEmpty()){
// 一直往左子树走,直到最左边的叶子结点
if(cur!=null){
stack.offerFirst(cur);
cur = cur.left;
}else{
// 进到这里说明左边走到头了
// 1.从栈中弹出(空左孩子的父节点)并保存
cur = stack.pollFirst();
result.add(cur.val);
// 2.访问右孩子节点
cur = cur.right;
}
}
return result;
}
}
后序遍历
// 递归法
// class Solution {
// public List<Integer> postorderTraversal(TreeNode root) {
// List<Integer> result = new ArrayList<>();
// postOrder(root,result);
// return result;
// }
// private void postOrder(TreeNode root,List<Integer> result){
// if(root==null){
// return;
// }
// postOrder(root.left,result);
// postOrder(root.right,result);
// result.add(root.val);
// }
// }
// 迭代法
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
if(root==null){
return result;
}
Deque<TreeNode> stack = new LinkedList<>();
// 根据前序遍历和中序遍历可以发现,先访问父节点的前序遍历比较简单
// 这里我们通过反转完成后序遍历:中 右 左 -> 左 右 中,这样的话和前序遍历是一个逻辑
stack.offerFirst(root);
while(!stack.isEmpty()){
TreeNode node = stack.pollFirst();
result.add(node.val);
if(node.left!=null){
stack.offerFirst(node.left);
}
if(node.right!=null){
stack.offerFirst(node.right);
}
}
// 反转
Collections.reverse(result);
return result;
}
}
层序遍历
整体思路就是,每弹出一个节点,就把其子节点(如果有的话)加入队列
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> result = new ArrayList<>();
if(root==null){
return result;
}
// 与深度遍历不同,层序遍历我们采用队列
Deque<TreeNode> queue = new LinkedList<>();
queue.offerLast(root);
while(!queue.isEmpty()){
// 定义subResult 存储每一层的结果
List<Integer> subResult = new ArrayList<>();
// 注意queue.size()会变化,不能直接放进循环
int curLevelLen = queue.size();
while(curLevelLen>0){
TreeNode node = queue.pollFirst();
subResult.add(node.val);
if(node.left!=null){
queue.offerLast(node.left);
}
if(node.right!=null){
queue.offerLast(node.right);
}
curLevelLen--;
}
result.add(subResult);
}
return result;
}
}