二叉树的之字形层序遍历
1、参考资料
https://www.nowcoder.com/practice/47e1687126fa461e8a3aff8632aa5559
2、题目要求
题目描述
给定一个二叉树,返回该二叉树的之字形层序遍历,(第一层从左向右,下一层从右向左,一直这样交替)
例如:给定的二叉树是
{3,9,20,#,#,15,7}
该二叉树之字形层序遍历的结果是
[
[3],
[20,9],
[15,7]
]
示例
输入
{1,#,2}
输出
[[1],[2]]
3、代码思路
基于双栈的层序遍历
-
我们可以使用
queue
对二叉树进行层序遍历,现在要求进行之字形层序遍历,即第一层正序输出,第二层逆序输出,第三层又正序输出,以此类推。。。 - 但凡牵涉到逆序,我们就会想到栈这个数据结构,因为栈先进后出,先进入栈的数据最后出栈,所以栈能实现逆序的效果
- 起初写代码的时候我卡壳了,因为我只用了一个栈,抠破脑袋也捋清思路,现在想想,这不挺简单的一个道理嘛~~~
-
假设我们现在遍历到二叉树第二层,首先,为了实现逆序遍历,二叉树第二层的节点肯定都保存在一个栈中(
stack1
),这是毋庸置疑的,那么下一层节点咋办呢?肯定不能往
stack1
里面塞,因为塞了之后就把
stack1
的栈顶给封住了,第二层剩余的节点就取不出来了,所以我们还需要一个栈(
stack2
)存储下一层的节点 -
在经历上述操作后,
stack1
变为了空栈,
stack2
存储了第三层的节点,然后我们接着遍历
stack2
,将第四层的节点存入
stack1
中 -
仔细想了想,我这里的设计思路还有点牛逼(自恋一下),引用
JVM
幸存者区的一句话:谁空谁是
to
,这点在我代码中也有体现,
stackOut
表示存储当前层节点的栈,
stackIn
表示存储下一层节点的栈,
stack1
和
stack2
的身份在
stackOut
和
stackIn
之间不停地切换 -
关于遍历的方向:从左往右遍历(正向遍历)时,我们需要先将当前节点的左节点
stackIn
中;从右往左遍历(反向遍历)时,我们需要先将当前节点的右节点
stackIn
中
举例说明
-
以下面这颗二叉树举例说明,先将根节点
1
压入
stack1
中1 / \ 2 3 / \ 4 5
-
首先遍历的方向为正向遍历(
isForward = true
,从左往右遍历)时-
此时
stack1
为
stackOut
,
stack2
为
stackIn
,遍历完成后
stack1
为空,
stack2
中存储着第二层的节点 -
遍历时不断
pop()
出
stackOut
中的节点,添加至
ArrayList
中,得到第一层的顺序遍历
1 <-------当前层 / \ 2 3 / \ 4 5
-
此时
-
遍历完第一层后转换方向,变为从右往左遍历(
isForward = false
),-
此时
stack2
为
stackOut
,
stack1
为
stackIn
,遍历完成后
stack2
为空,
stack1
中存储着第三层的节点 -
遍历时不断
pop()
出
stackOut
中的节点,添加至
ArrayList
中,得到第二层的逆序遍历
1 / \ 2 3 <-------当前层 / \ 4 5
-
此时
-
以此类推
4、代码实现
代码
class Solution {
public ArrayList<ArrayList<Integer>> zigzagLevelOrder(TreeNode root) {
ArrayList<ArrayList<Integer>> zigzagOrder = new ArrayList<>();
// Guard safe
if (root == null) {
return zigzagOrder;
}
// 双栈
Deque<TreeNode> stack1 = new LinkedList<>();
Deque<TreeNode> stack2 = new LinkedList<>();
stack1.push(root); // 将根节点压入栈中
boolean isForword = true; // 初始顺序为从左往右遍历
// 但凡只要有一个栈中还有元素,则证明当前层还有节点
while (stack1.isEmpty() == false || stack2.isEmpty() == false) {
// 谁空谁来存储下一层节的点,谁不空谁存储了当前层节点
Deque<TreeNode> stackOut = stack1.isEmpty() ? stack2 : stack1;
Deque<TreeNode> stackIn = stack1.isEmpty() ? stack1 : stack2;
zigzagOrder.add(new ArrayList<>());
// 遍历完当前层的节点
while (stackOut.isEmpty() == false) {
// 栈顶节点出栈
TreeNode curNode = stackOut.pop();
// 添加至 ArrayList
zigzagOrder.get(zigzagOrder.size() - 1).add(curNode.val);
if (isForword) {
// 如果方向是从左往右,则先遍历当前节点的左节点
pushNode(stackIn, curNode.left);
pushNode(stackIn, curNode.right);
} else {
// 如果方向是从右往左,则先遍历当前节点的右节点
pushNode(stackIn, curNode.right);
pushNode(stackIn, curNode.left);
}
}
isForword = !isForword; // 改变方向
}
return zigzagOrder;
}
private void pushNode(Deque<TreeNode> stack, TreeNode node) {
if (node != null) {
stack.push(node);
}
}
}
class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
版权声明:本文为oneby1314原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。