项目地址:https://github.com/SpecialYy/Sword-Means-Offer
问题
请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
解析
首先我们要知道如何层级遍历且按行输出,知道这个原理后,再处理之字形就简单多了。
层级遍历:依次打印二叉树每一层的节点。先打印根节点,然后打印根节点的左右孩子,然后再打印这些孩子的左右孩子,直到最后一层为止。
如上图,层次遍历的顺序且带换行的形式为:
1
2,3
4,5,6,7
具体如何做呢?我们首先观察层次遍历的形式,发现右孩子总是先与左孩子出现,我们一般遍历时也是先左孩子后右孩子,所以符合先进先出的要求,很明显这里采用队列的数据结构比较合适。还有个问题我们如何控制换行呢,也就是我们怎么能做到打印出的形式符合原先树的层级关系呢?显然我们只要保证在出队时只出当前行的节点即可,一种做法时在出队列时首先获取当前队列的长度,因为这时队列里的节点就是当前行的节点。由于队列的先入先出的特性,我们对于出队的节点的左孩子和右孩子进队的行为不会影响获取当前层的节点的操作,因为我们事先获取了长度,所以不会出现任何差错。
老规矩,举个例子,拿上图为例:
- 首先根节点1入队列
- 获取队列的长度,长度为1,说明当前层的节点数为1,打印1,然后把1的左孩子2和右孩子3入队列
- 获取队列的长度,长度为2,说明当前层的节点数为2,依次出队2,3,同时把他们的左右孩子4,5,6和7入队
- 获取队列的长度,长度为4,说明当前层的节点数为4,依次出队4,5,6和7,因为他们都没有孩子,所以没有入队操作
- 队列为空,结束
基于以上的算法步骤,即可确保层次遍历且自带换行操作,保证了打印的序列与二叉树形式一致。
思路一
显示之字形的打法就是对偶数层特殊处理,即翻转当前行的节点即可。还是上图,第二层正常的打印顺序为2,3,翻转后为3,2, 所以上图的之字型打印序列为:
1
3,2
4,5,6,7
public ArrayList<ArrayList<Integer>> Print(TreeNode pRoot) {
ArrayList<ArrayList<Integer>> result = new ArrayList<>();
if (pRoot == null) {
return result;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(pRoot);
//表示第几层,决定每一行节点的方向
int index = 0;
while(!queue.isEmpty()) {
index++;
//获取当前层节点的个数
int length = queue.size();
//依次弹出当前层,并用list保存当前层的节点
ArrayList<Integer> row = new ArrayList<>();
for (int i = 0; i < length; i++) {
TreeNode node = queue.poll();
row.add(node.val);
if (node.left != null) {
queue.add(node.left);
}
if (node.right != null) {
queue.add(node.right);
}
}
//若是偶数行,则反序当前层节点
if ((index & 1) == 0) {
Collections.reverse(row);
}
result.add(row);
}
return result;
}