// 前序遍历 // 1、确定递归函数的参数和返回值 publicvoidpreorder(TreeNode root, List<Integer> result){ // 2、确定终止条件 if(root == null) return; // 3、确定单层递归的逻辑:N L R,先取中节点 result.add(root.val); // N preorder(root.left,result); // L preorder(root.right,result); // R }
// 中序遍历 // 1、确定递归函数的参数和返回值 publicvoidinorder(TreeNode root, List<Integer> result){ // 2、确定终止条件 if(root == null) return; // 3、确定单层递归的逻辑:L N R inorder(root.left,result); // L result.add(root.val); // N inorder(root.right,result); // R }
// 后序遍历 // 1、确定递归函数的参数和返回值 publicvoidpostorder(TreeNode root, List<Integer> result){ // 2、确定终止条件 if(root == null) return; // 3、确定单层递归的逻辑:L R N postorder(root.left,result); // L postorder(root.right,result); // R result.add(root.val); // N }
前、中、后序的 递归遍历 非常简单,但是 非递归遍历 会有点难度
【DFS】的迭代遍历(非递归遍历)
递归的实现就是:每一次递归调用都会把函数的局部变量、参数值和返回地址等压入调用栈中
所以也能用 栈 实现二叉树的前后中序遍历
前序遍历 N L R
入栈的顺序是 N R L,弹出 N,再入栈 R L,出栈顺序才会是 N L R
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
// N L R // 入栈的顺序是 N R L,弹出 N,再入栈 R L,出栈顺序才会是N L R public List<Integer> preorderTraversal(TreeNode root){ List<Integer> result = newArrayList<>(); if(root == null) return result; Stack<TreeNode> stack = newStack<>(); stack.push(root); // N入栈 while(!stack.isEmpty()){ TreeNodenode= stack.pop(); // N出栈 result.add(node.val); if(node.right != null) stack.push(node.right); if(node.left != null) stack.push(node.left); } return result; }
后序遍历 L R N
入栈的顺序是 N L R,弹出 N,再入栈 L R,出栈顺序才会是 N R L,再 翻转 为 L R N
翻转函数为 Collections.reverse()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// L R N // 入栈的顺序是 N L R,弹出 N,再入栈 L R,出栈顺序才会是N R L,再翻转为 L R N public List<Integer> postorderTraversal(TreeNode root){ List<Integer> result = newArrayList<>(); if(root == null) return result; Stack<TreeNode> stack = newStack<>(); stack.push(root); // N入栈 while(!stack.isEmpty()){ TreeNodenode= stack.pop(); // N出栈 result.add(node.val); if(node.left != null) stack.push(node.left); if(node.right != null) stack.push(node.right); } Collections.reverse(result); // 翻转结果,N R L -> L R N return result; }
中序遍历 L N R (与前后序逻辑不同)
前后序 要 访问的元素 和 要处理的元素 顺序是一致的,都是 中间节点。所以代码简洁
使用迭代法中序遍历,就需要借用指针的遍历来帮助访问节点,栈则用来处理节点上的元素
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
// L N R // 入栈的顺序是 L R public List<Integer> inorderTraversal(TreeNode root){ List<Integer> result = newArrayList<>(); if(root == null) return result; Stack<TreeNode> stack = newStack<>(); TreeNodecur= root; // 记录访问节点 while(cur != null || !stack.isEmpty()){ if(cur != null){ // 访问到最底层 stack.push(cur); cur = cur.left; // 继续找左孩子 }else{ cur = stack.pop(); // 要处理的数据 result.add(cur.val); // N cur = cur.right; // R } } return result; }
【BFS] 层次遍历(广度优先)
借助 队列
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
public List<List<Integer>> res = newArrayList<>(); // 保存最终结果