思路,首先把根节点存储,这是树的第 0 层。
第二层,由于要从右向左打印,而在第一层保存数据的时候,我们就需要把当前的节点的右孩子放入队列,左孩子后放入队列。
第二次,由于要从左向右打印,所以,我们必须先获取第一层的左节点的左节点。所以在第二层我们就不能使用队列了,而是栈!
重新梳理思路,
第二层我们依旧左子节点先入栈,右子节点后入栈,这样,在第三层时我们就可以先获得右子节点。
第三层,当前栈顶为右子节点,我们必须让右子节点的右孩子先入栈,左孩子后入栈。右子节点处理后,就是左子节点,左子节点的右孩子先入栈,左孩子后入栈,这样下一层获取的时候,就是左孩子先获得了。
第四层,同样,先让左子孩子入栈,再让右孩子入栈。下一层就可以从右向左打印。
第五层,右孩子先入栈。。。
现在就可以总结出来规律了,第二层左子节点先入栈,下一层就是右子节点先入站,再下一层是左子节点先入站。所以每一次都是取反!只要当前的boolean值是true,我们就让它从左向右的入栈,false,就从右向左的入栈。
而每一层的操作都是一个递归的过程。
public static List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> result = new ArrayList<>();
if(root == null) return result;
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
boolean leftGoRight = true;
printLikeZ(result,stack,leftGoRight);
return result;
}
public static void printLikeZ(List result,Stack<TreeNode> stack,boolean leftGoRight){
//保存下一层的节点
Stack<TreeNode> newStack = new Stack();
//保存当前节点的值
ArrayList<Integer> currentVaules = new ArrayList<>();
while(!stack.isEmpty()){
TreeNode current = stack.pop();
currentVaules.add(current.val);
//如果当前的是从左向右的保存子节点
if(leftGoRight){
if(current.left != null)
newStack.push(current.left);
if(current.right != null)
newStack.push(current.right);
}
//如果不是
else{
if(current.right != null)
newStack.push(current.right);
if(current.left != null)
newStack.push(current.left);
}
}
//如果当前保存的节点值个数不为0,那么就将其加入结果集
if(!currentVaules.isEmpty()){
result.add(currentVaules);
}
//如果有下一个节点,那么就递归
if(!newStack.isEmpty()){
//下一次按反向入栈。
printLikeZ(result,newStack,!leftGoRight);
}
}