【算法】二叉树的层次遍历及其衍生问题(5)
(一)二叉树的层次遍历
二叉树的层序遍历(也叫广度优先遍历)的要求是:按二叉树的层序次序(即从根结点层至叶结点层),同一层中按先左子树再右子树的次序遍历二叉树。
层次遍历的特点是,在所有未被访问结点的集合中,排列在已访问结点集合中最前面结点的左子树的根结点将最先被访问,然后是该结点的右子树的根结点。这样,如果把已访问的结点放在一个队列中,那么,所有未被访问结点的访问次序就可以由存放在队列中的已访问结点的出队列次序决定。因此可以借助队列实现二叉树的层序遍历。
层次遍历算法如下:
(1)初始化设置一个队列;
(2)把根结点指针入队列;
(3)当队列非空时,循环执行步骤(3.a-3.c);
(3.a)出队列取得一个结点指针,访问该结点;
(3.b)若该结点的左子树非空,则将该结点的左子树指针入队列;
(3.c)若该结点的右子树非空,则将该结点的右子树指针入队列;
(4)结束。
(二)从上往下打印二叉树
public class Solution {
public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {
/*二叉树的层次遍历,使用队列实现*/
ArrayList<Integer> res=new ArrayList<>();
if(root==null)
return res;
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
while(!queue.isEmpty()){
TreeNode temp=queue.poll();
res.add(temp.val);
if(temp.left!=null)
queue.add(temp.left);
if(temp.right!=null)
queue.add(temp.right);
}
return res;
}
}
(三)把二叉树打印成多行
public class Solution {
ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
/*层次遍历:队列实现*/
ArrayList<ArrayList<Integer>> res = new ArrayList<>();
if(pRoot==null)
return res;
Queue<TreeNode> queue=new LinkedList<>();
queue.add(pRoot);
while(!queue.isEmpty()){
ArrayList<Integer> temp=new ArrayList<>();
int len=queue.size(); //当前队列中的节点个数,也就是当前层的节点个数
for(int i=0;i<len;i++){ //依次取出这len个节点
TreeNode cur=queue.poll();
temp.add(cur.val);
if(cur.left!=null)
queue.add(cur.left);
if(cur.right!=null)
queue.add(cur.right);
}
res.add(temp);
}
return res;
}
}
(四)二叉树的左右视图
二叉树的左右视图就是从左边(或者右边)看二叉树能够看到的序列,所以其实就是每一层的第一个节点或者最后一个结点,本质上仍然是层序遍历。
参考LeetCode第199题:199. Binary Tree Right Side View(题目难度:medium)
class Solution {
public List<Integer> rightSideView(TreeNode root) {
List<Integer> res=new ArrayList<>();
if(root==null)
return res;
Queue<TreeNode> queue=new LinkedList<>();
queue.add(root);
while(!queue.isEmpty()){
int len = queue.size(); //当前队列长度,也就是当前层的节点个数
for(int i=0;i<len;i++){
TreeNode temp=queue.poll();
if(i==len-1) //每一行最后一个
res.add(temp.val);
if(temp.left!=null)
queue.add(temp.left);
if(temp.right!=null)
queue.add(temp.right);
}
}
return res;
}
}
(五)之字形打印二叉树
public class Solution {
public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
/*
思路:之字形打印,用两个栈来实现
打印奇数行时,将他的左右节点保存到另一个栈中,先左后右
打印偶数行时,同样将左右节点保存到栈中,先右后左
*/
ArrayList<ArrayList<Integer>> res=new ArrayList<>();
if(pRoot==null)
return res;
Stack[] stack=new Stack[2];
stack[0]=new Stack();
stack[1]=new Stack();
int num=1;
stack[1].push(pRoot);
while(!stack[0].isEmpty() || !stack[1].isEmpty()){
int cur=num%2;
ArrayList<Integer> row=new ArrayList<>();
while(!stack[cur].isEmpty()){
TreeNode temp=(TreeNode)stack[cur].pop();
row.add(temp.val);
if(cur==1){ //奇数行,先左再右
if(temp.left!=null)
stack[0].push(temp.left);
if(temp.right!=null)
stack[0].push(temp.right);
}else{ //偶数行,先右后左
if(temp.right!=null)
stack[1].push(temp.right);
if(temp.left!=null)
stack[1].push(temp.left);
}
}
res.add(row);
num++;
}
return res;
}
}
(六) 二叉树的层平均值
题目(Easy):二叉树的层平均值
题目描述:
给定一个非空二叉树, 返回一个由每层节点平均值组成的数组.
示例 1:
输入:
3
/ \
9 20
/ \
15 7
输出: [3, 14.5, 11]
解释:
第0层的平均值是 3, 第1层是 14.5, 第2层是 11. 因此返回 [3, 14.5, 11].
解题思路:
本题是二叉树层次遍历的变种。注意防止求和时的溢出。
class Solution {
public List<Double> averageOfLevels(TreeNode root) {
List<Double> res=new ArrayList<>();
if(root==null)
return res;
Queue<TreeNode> queue=new LinkedList<>();
queue.add(root);
while(!queue.isEmpty()){
int num=queue.size();
long sum=0; //注意防止溢出
for(int i=0;i<num;i++){
TreeNode temp=queue.poll();
sum+=temp.val;
if(temp.left!=null)
queue.add(temp.left);
if(temp.right!=null)
queue.add(temp.right);
}
res.add(sum*1.0/num);
}
return res;
}
}
涉及题目:
leetCode102、Binary Tree Level Order Traversal
博学 审问 慎思 明辨 笃行