基本层序遍历与变换
仅输出全部元素
先访问根节点,把其左右孩子放进队列。出队,入队左右孩子。直到队列为空。
public List<Integer> levelOrder(TreeNode root) { if(root==null){ return new ArrayList<>();//List不能被实例化,它是接口,不是class } LinkedList<TreeNode> queue=new LinkedList<>(); queue.add(root); List<Integer> res=new ArrayList<Integer>(); while(queue.size()>0){ TreeNode t=queue.remove(); res.add(t.val); //加入的是树节点的值 if(t.left!=null){ queue.add(t.left); } if(t.right!=null){ queue.add(t.right); } } return res; }
由此可见,队列就是一个缓存的作用。
⭐⭐⭐lc102二叉树的层序遍历
将每层的元素分开。
public List<List<Integer>> levelOrder(TreeNode root) { List<List<Integer>> ret=new ArrayList<>();//List不能被实例化,它是接口,不是class if(root==null){ return ret; } LinkedList<TreeNode> queue=new LinkedList<>(); queue.add(root); while(queue.size()>0){ List<Integer> res=new ArrayList<Integer>(); int cnt=queue.size();//获取当前队列的长度,即当前这一层的元素个数 for(int i=1;i<=cnt;i++){ TreeNode t=queue.remove(); res.add(t.val); //加入的是树节点的值 if(t.left!=null){ queue.add(t.left); } if(t.right!=null){ queue.add(t.right); } } ret.add(res); } return ret; } //官方的,用到queue class Solution { public List<List<Integer>> levelOrder(TreeNode root) { List<List<Integer>> ret = new ArrayList<List<Integer>>(); if (root == null) { return ret; } Queue<TreeNode> queue = new LinkedList<TreeNode>(); queue.offer(root); while (!queue.isEmpty()) { List<Integer> level = new ArrayList<Integer>(); int currentLevelSize = queue.size(); for (int i = 1; i <= currentLevelSize; ++i) { TreeNode node = queue.poll(); level.add(node.val); if (node.left != null) { queue.offer(node.left); } if (node.right != null) { queue.offer(node.right); } } ret.add(level); } return ret; } }
lc107自底向上遍历二叉树
在遍历完一层节点之后,将存储该层节点值的列表添加到结果列表的头部。ret.add(0,temp);
在Java中,
List
接口有一个add(int index, E element)
方法,它可以在指定的索引位置插入一个元素E
到列表中。通过将索引设置为0,你可以将元素插入到列表的开头位置。这就是代码中ret.add(0, temp)
的实现方式。
public List<List<Integer>> levelOrderBottom(TreeNode root) { List<List<Integer>> ret=new LinkedList<List<Integer>>(); //LinkedList if(root==null){ return ret; } Queue<TreeNode> queue=new LinkedList<TreeNode>(); queue.offer(root); while(!queue.isEmpty()){ List<Integer> temp=new ArrayList<Integer>(); int size=queue.size(); for(int i=0;i<size;i++){ TreeNode t=queue.poll(); temp.add(t.val); TreeNode left=t.left,right=t.right; if(left!=null){ queue.offer(left); } if(right!=null){ queue.offer(right); } } ret.add(0,temp); } return ret; }
lc103锯齿遍历
public List<List<Integer>> zigzagLevelOrder(TreeNode root) { List<List<Integer>> ret=new LinkedList<>(); if(root==null){ return ret; } Queue<TreeNode> queue=new LinkedList<>(); //缓存队列 queue.offer(root); boolean isLeft=true; //加标志位判断 while(!queue.isEmpty()){ Deque<Integer> temp=new LinkedList<>(); //层双端队列 int cnt=queue.size(); for(int i=0;i<cnt;i++){ TreeNode t=queue.poll(); if(isLeft){ temp.offerLast(t.val); //offerLast } else { temp.offerFirst(t.val); //offerFirst } if(t.left!=null){ queue.offer(t.left); } if(t.right!=null){ queue.offer(t.right); } } //Deque<Integer> cannot be converted to List<Integer> // ret.add(temp); ret.add(new LinkedList<Integer>(temp)); isLeft=!isLeft; } return ret; }
lc429 N叉树的遍历
和二叉树思路类似,只是每次要把所有孩子入队。
下面是使用
ArrayDeque
作为队列的一些优点:
-
性能好:
ArrayDeque
的性能通常比LinkedList
好,尤其是在大部分情况下,因为它是基于数组实现的,随机访问元素的速度更快。 -
内存效率: 相对于
LinkedList
,ArrayDeque
使用的内存通常更少,因为它不需要为每个元素存储两个引用(前一个和后一个元素的引用)。 -
简单性:
ArrayDeque
更容易使用,因为它没有LinkedList
的额外复杂性。
public List<List<Integer>> levelOrder(Node root) { List<List<Integer>> ret=new ArrayList<>(); if(root==null){ return ret; } Queue<Node> queue=new ArrayDeque<Node>(); queue.offer(root); while(!queue.isEmpty()){ int cnt=queue.size(); List<Integer> temp=new ArrayList<>(); for(int i=0;i<cnt;i++){ Node t=queue.poll(); temp.add(t.val); for(Node child:t.children){ //不只是入队左孩子和右孩子了,把所有孩子都入队 queue.offer(child); } } ret.add(temp); } return ret; }