描述
给定一个二叉树,返回该二叉树的之字形层序遍历,(第一层从左向右,下一层从右向左,一直这样交替)
例如:给定的二叉树是{1,2,3,#,#,4,5},该二叉树之字形层序遍历的结果是[[1],[3,2],[4,5]]
/* TreeNode类的代码
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
示例
input1:
{8,6,10,5,7,9,11}
output1:
[[8],[10,6],[5,7,9,11]]
input2:
{1,2,3,4,5}
output2:
[[1],[3,2],[4,5]]
思路
根据题目的要求,需要对二叉树进行层序遍历同时区分奇偶层。该题的要点为:保存每一层的结果(从1开始),保存的顺序为:奇数层从左往右,偶数层从右到左。按照该要点,可以考虑以下方法:
- 使用队列:
Queue
保存每一层的结果,每次遍历将poll
出当前层个数的结点,另外需要使用一个deep
记录层数:奇数层调用Array.add(e)
达到从左到右,偶数层调用Array.add(e)
然后Collections.reverse(arr)
进行反序达到从右到左的顺序 - 使用双栈:一个保存奇数层,一个保存偶数层
1、单向队列:偶数层反序
该方法参考 剑指offer:JZ60 把二叉树打印成多行 该题目中也可以使用ArrayList.add(0, e)
来达到反序的目的,但是ArrayList
中数组整体移动的次数较多。
import java.util.*;
public class Solution {
public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
ArrayList<ArrayList<Integer>> list = new ArrayList<>();
if(pRoot == null) return list;
TreeNode tmp = null;
int size = 0, i = 0, deep = 1;
Queue<TreeNode> que = new LinkedList<>();
ArrayList<Integer> arr = null;
que.offer(pRoot);
while(!que.isEmpty()){
size = que.size();//获取当前层的结点个数
i = 0;
arr = new ArrayList<>();
while(i++ < size){
tmp = que.poll();
arr.add(tmp.val);
if(tmp.left != null) que.offer(tmp.left);
if(tmp.right != null) que.offer(tmp.right);
}
if((deep & 1) == 0) Collections.reverse(arr);
list.add(arr);
deep++;
}
return list;
}
}
2、双端队列:奇偶分离
双端队列可以保证奇数层时从队头取结点,偶数层时从队尾取元素。
import java.util.*;
public class Solution {
public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
ArrayList<ArrayList<Integer>> list = new ArrayList<>();
if(pRoot == null) return list;
TreeNode tmp = null;
int size = 0, i = 0, deep = 1;
Deque<TreeNode> deque = new LinkedList<>();
ArrayList<Integer> arr = null;
deque.offer(pRoot);
while(!deque.isEmpty()){
size = deque.size();//获取当前层的结点个数
i = 0;
arr = new ArrayList<>();
while(i++ < size){
if((deep & 1) == 1){//奇数层
tmp = deque.removeFirst();
if(tmp.left != null) deque.addLast(tmp.left);
if(tmp.right != null) deque.addLast(tmp.right);
}
else{
tmp = deque.removeLast();
if(tmp.right != null) deque.addFirst(tmp.right);
if(tmp.left != null) deque.addFirst(tmp.left);
}
arr.add(tmp.val);
}
list.add(arr);
deep++;
}
return list;
}
}
3、双栈:奇偶层分离
该方法利用栈的特性:先进后出。因此按照奇偶栈可以实现本题:
(1)奇数栈加入根结点,当前深度设为1。
(2)当前循环为奇数层,则遍历奇数栈中元素,同时按照从左到右的顺序将下一层结点加入到偶数栈(因而偶数栈遍历时结点从右到左)
(3)当前循环为偶数层,则遍历偶数栈中元素,同时按照从右到左的顺序将下一层结点加入到奇数栈(因而奇数栈遍历时结点从左到右)
import java.util.*;
public class Solution {
public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
ArrayList<ArrayList<Integer>> list = new ArrayList<>();
if(pRoot == null) return list;
TreeNode tmp = null;
int size = 0, i = 0, deep = 1;
Stack<TreeNode> st_odd = new Stack<>();
Stack<TreeNode> st_even = new Stack<>();
ArrayList<Integer> arr = null;
st_odd.push(pRoot);
while(!st_odd.isEmpty() || !st_even.isEmpty()){
i = 0;
arr = new ArrayList<>();
if((deep & 1) == 1){//奇数层
size = st_odd.size();
while(i++ < size){
tmp = st_odd.pop();
arr.add(tmp.val);
//下一层是偶数层,因此偶数栈先加左子树,保证右边的结点在栈顶
if(tmp.left != null) st_even.push(tmp.left);
if(tmp.right != null) st_even.push(tmp.right);
}
}
else{//偶数层
size = st_even.size();
while(i++ < size){
tmp = st_even.pop();
arr.add(tmp.val);
//下一层是奇数层,因此奇数栈先加右子树,保证左边的结点在栈顶
if(tmp.right != null) st_odd.push(tmp.right);
if(tmp.left != null) st_odd.push(tmp.left);
}
}
list.add(arr);
deep++;
}
return list;
}
}