二叉树遍历
题目链接
leetcode-144:前序遍历
leetcode-94:中序遍历
leetcode-145:后序遍历
leetcode-102:层序遍历
二叉树的深度遍历
递归遍历
- 前序遍历
class Solution {
List<Integer> res = new LinkedList<>();
public List<Integer> preorderTraversal(TreeNode root) {
traverse(root);
return res;
}
void traverse(TreeNode root) {
if(root == null) return;
res.add(root.val);
traverse(root.left);
traverse(root.right);
}
}
- 中序遍历
class Solution {
List<Integer> res = new LinkedList<>();
public List<Integer> inorderTraversal(TreeNode root) {
traverse(root);
return res;
}
void traverse(TreeNode root) {
if(root == null) return;
traverse(root.left);
res.add(root.val);
traverse(root.right);
}
}
- 后序遍历
class Solution {
List<Integer> res = new LinkedList<>();
public List<Integer> postorderTraversal(TreeNode root) {
traverse(root);
return res;
}
void traverse(TreeNode root) {
if(root == null) return;
traverse(root.left);
traverse(root.right);
res.add(root.val);
}
}
- 总结
(1)、迭代切勿纠结于细节,而是应该追求逻辑的自洽
(2)、二叉树的模板框架:
void traverse(TreeNode root) {
if(root == null) return;//判断“归”的条件
//前序代码位置
traverse(root.left);
//中序代码位置
traverse(root.right);
//后序代码位置
}
(3)、递归函数我粗略的认为就是循环,类似于数组的遍历,只不过这个是二叉树的遍历,以下代码就是循环的框架,粗略认为只要traverse
(或者其他名词)同时出现三次就算是完成了循环,然后相对应的数组循环有i<nums.length
的条件,那么递归也应该有终止条件,即if(root == null) return
,数组中也有循环主体,即是你要做的事情,相应的递归函数中,前序、中序、或者后序代码位置就是你的循环主体。
void traverse(TreeNode root) {
traverse(root.left);
traverse(root.right);
}
- 递归的三个部分:
(1)、确定函数的返回值以及函数的定义
(2)、确定终止条件,做到有递有归
(3)、确定单层递归的逻辑,即假设你自己站在节点上,你需要做什么,你需要知道什么,将这些代码写到前序、中序、或者后序代码位置,以此解题。
迭代遍历
- 前序遍历
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
if(root == null) return new LinkedList<Integer>();
LinkedList<TreeNode> stack = new LinkedList<>();
LinkedList<Integer> res = new LinkedList<>();
stack.push(root);
while(!stack.isEmpty()) {
TreeNode curNode = stack.pop();
res.add(curNode.val);//前序代码位置
if(curNode.right != null) {
stack.push(curNode.right);//遍历左子树
}
if(curNode.left != null) {
stack.push(curNode.left);//遍历右子树
}
}
return res;
}
}
- 中序遍历
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
if(root == null) return new LinkedList<Integer>();
LinkedList<TreeNode> stack = new LinkedList<>();
TreeNode curNode = root;
LinkedList<Integer> res = new LinkedList<>();
while(curNode != null || !stack.isEmpty()) {
while(curNode != null) {
stack.push(curNode);
curNode = curNode.left;//遍历左子树
}
curNode = stack.peek();
res.add(curNode.val);//中序位置代码
curNode = curNode.right;//遍历右子树
stack.pop();
}
return res;
}
}
- 后序遍历
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
if(root == null) return new LinkedList<Integer>();
List<Integer> res = new LinkedList<>();//存出二叉树节点
LinkedList<TreeNode> stack = new LinkedList<>();//维护一个栈
TreeNode curNode = root;//维护一个当前节点
TreeNode visitNode = root;//维护一个已经访问节点
while(curNode != null || !stack.isEmpty()) { //栈不为空或者当前节点不是叶子结点
while(curNode != null) {
stack.push(curNode);//入栈
curNode = curNode.left;//遍历左子树
}
curNode = stack.peek();
if(curNode.right != null && curNode.right != visitNode) {
curNode = curNode.right;//遍历右子树
} else {
res.add(curNode.val);//后序代码位置
visitNode = curNode;//当前节点设为已访问节点
curNode = null;//当前节点设为空,防止再次访问
stack.pop();//出栈
}
}
return res;
}
}
- 总结
(1)、上述三种迭代二叉树的方式均需要维护一个栈stack
,这是因为递归正是栈的体现。
(2)、前序迭代需要stack
,中序迭代需要stack
,curNode
,前序迭代需要stack
,curNode
,visitNode
。
(3)、代码书写时,需要注意stack<TreeNode>
,以及if(root == null) return new LinkedList<Integer>()
不要写错。
(4)、前序遍历的代码是先右子树,再左子树,中序和后序都是先左子树再右子树。
二叉树的广度遍历
层序遍历
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> result = new ArrayList<>();
if(root == null) return result;
LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
queue.offer(root);
while(!queue.isEmpty()) {
int n = queue.size();//当前队列的大小
List<Integer> list = new ArrayList<>();
for(int i=0; i<n; i++) {
TreeNode curNode = queue.poll();
list.add(curNode.val);
if(curNode.left != null) {
queue.offer(curNode.left);//遍历左子树
}
if(curNode.right != null) {
queue.offer(curNode.right);//遍历右子树
}
}
result.add(list);
}
return result;
}
}
- 总结
(1)、层序遍历和前序遍历很像,代码几乎一样,前者使用单向队列,先遍历左子树,后遍历右子树;后者使用栈,先遍历右子树,后遍历左子树。
(2)、层序遍历在循环体内需要维护一个队列的大小,也可以不维护,视情况而定。
环环无敌大可爱
😄