题目
给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。
思路
层序遍历——>BFS队列
下面对二叉树进行DFS遍历和BFS遍历的代码进行比较:
DFS遍历,使用递归:
void dfs(TreeNode root) {
if (root == null) {
return;
}
dfs(root.left);
dfs(root.right);
}
BFS遍历,使用队列数据结构:
void bfs(TreeNode root) {
Queue<TreeNode> queue = new ArrayDeque<>();
queue.add(root);
while (!queue.isEmpty()) {
TreeNode node = queue.poll(); // Java 的 pop 写作 poll()
if (node.left != null) {
queue.add(node.left);
}
if (node.right != null) {
queue.add(node.right);
}
}
}
从代码直观来看,DFS的代码比BFS简洁太多,因为递归的方式是隐含的使用了系统的栈,不需要我们自己手动去维护一个数据结构;而BFS需要手动维护队列。
如果只是简单地将二叉树遍历一遍,那么 DFS 显然是更方便的选择,但是如果考虑层序遍历,那么BFS是优先选择。
BFS主要用于:层序遍历→最短路径,而且「BFS 遍历」、「层序遍历」、「最短路径」
实际上是递进的关系。在 BFS 遍历的基础上区分遍历的每一层,就得到了层序遍历。在层序遍历的基础上记录层数,就得到了最短路径。
对于层序遍历,使用BFS的顺序是一致的,但是最终结果有所区别,要考虑以下问题:
- 层序遍历要求区分每一层,也就是返回一个二维数组。
- 而BFS 的遍历结果是一个一维数组,无法区分每一层。
所以需要修改一下代码,在每一层遍历开始前,先记录队列中的结点数量 n(也就是这一层的结点数量),然后一口气处理完这一层的 n 个结点。比如队里中有2,3,那么 n = 2,先考虑2,把2的左右孩子加入队列,2出队列;再考虑3,把3的左右孩子加入队列,3出队列,然后进入到下一层,记录下一层将诶点数量,n = 4,以此类推…
class Solution {
//BFS:借助队列
public List<List<Integer>> levelOrder(TreeNode root){
List<List<Integer>> res = new ArrayList<List<Integer>>();//记录最终结果
Queue<TreeNode> queue = new LinkedList<>();//负责遍历二叉树,其中Queue是一个接口,不能实例化,只能创建实现了这个接口的实现类对象
if (root != null) {
queue.add(root);//根节点入队
}
while(!queue.isEmpty()){
List<Integer> level = new ArrayList<>();//level记录每一层的节点数,如[1],[2,3],[4,5,6],多个level组成最终的res
int n = queue.size();//记录当前层节点个数(因为队列中始终维护一层的元素),控制队列弹出节点数量,如第一层一个元素则队列出一个元素,第二层两个元素,则队列出两个元素
//这里要注意,java 中 while(n--)是会报错的,或者直接用for循环:for (int i = 0; i < n; i++),这里的i无实际意义,只是为了循环n次
//要么用while()一定要加上判断while(n-- > 0)
while(n-- > 0){//控制队列出元素的个数,如第二层元素个数为2则队列弹出两个元素,保证处理完当前层再去遍历下一层
TreeNode node = queue.poll();//poll返回队首元素
level.add(node.val);//放到一维数组中
if(node.left != null) queue.add(node.left);//如果左孩子不为空,则加入队列
if(node.right != null) queue.add(node.right);//如果右孩子不为空,则加入队列
}
res.add(level);//将多个一维数组放到二维数组中
}
return res;
}
}
层序遍历模板:
class Solution {
public int[] levelOrder(TreeNode root){//返回值根据题目而定,可以是int[],也可以是List<Integer>等等
List<Integer> res = new ArrayList<>();
Queue<TreeNode> queue = new LinkedList<>();//负责遍历二叉树
if (root != null) {
queue.add(root);
}
while(!queue.isEmpty()){
TreeNode node = queue.poll();
res.add(node.val);
if(node.left != null) queue.add(node.left);
if(node.right != null) queue.add(node.right);
}
int n = res.size();
int[] ans = new int[n];
for(int i = 0; i < n; i++ ){
ans[i] = res.get(i);
}
return ans;
}
}