对于二叉树一般是按深度生成和遍历,比如使用递归方法进行先序遍历、中序遍历、后序遍历。这次我们按层次生成和遍历二叉树。
这种遍历方式关键在于需要使用一个队列保存“已处理该节点,但还没处理它的子节点”这样的节点。
# Python代码
# Definition for singly-linked list.
class BinTree(object):
def __init__(self, x):
self.val = x
self.left = None
self.right = None
class Solution(object):
# 按层次建立二叉树
def createBinTree(self, inputList):
# 尚未设置子节点的节点列表
nodeList = []
if (inputList == None) or (len(inputList) == 0):
return None
# 取出根元素
value = inputList.pop(0)
root = BinTree(value)
nodeList.append(root)
# 结束条件:所有值不为“#”的节点都设置了子节点,即nodeList为空
while len(nodeList) != 0:
leftValue = inputList.pop(0)
rightValue = inputList.pop(0)
if leftValue != '#' and rightValue != '#':
nodeLeft = BinTree(leftValue)
nodeRight = BinTree(rightValue)
# 每次取出两个节点,加入到 “未设置子节点的节点列表”
nodeList.append(nodeLeft)
nodeList.append(nodeRight)
nodeList[0].left = nodeLeft
nodeList[0].right = nodeRight
# 为节点设置子节点后移出队列
nodeList.pop(0)
# 若值为#,不需要处理,默认情况下节点的左右节点都为None
elif leftValue == '#' and rightValue != '#':
nodeRight = BinTree(rightValue)
nodeList.append(nodeRight)
nodeList[0].right = nodeRight
nodeList.pop(0)
elif rightValue == '#' and leftValue != '#':
nodeLeft = BinTree(leftValue)
nodeList.append(nodeLeft)
nodeList[0].left = nodeLeft
nodeList.pop(0)
else:
nodeList.pop(0)
return root
# 按层次遍历二叉树
def traverseBinTree(self, root):
nodeList = []
# 先将根节点加入队列中
if root != None:
nodeList.append(root)
while len(nodeList) != 0:
# 输出队列第一个节点值,并将该节点的左右子节点加入队列
node = nodeList.pop(0)
if node == None:
print('#')
continue
print(node.val)
leftNode = node.left
rightNode = node.right
nodeList.append(leftNode)
nodeList.append(rightNode)
s = Solution()
root = s.createBinTree(inputList = ['A', 'B', 'C', '#', 'D', '#', 'E', 'F', '#', '#', '#', '#', '#'])
s.traverseBinTree(root)
再进一步,不仅要按层次遍历二叉树,还要将每一层分别放在一个列表中。[ [3], [9,20], [15,7] ],实现这个要求重点在于确定何时一层遍历完成。每层二叉树的节点数目(含null节点)为上一层不含null节点的数目 * 2。可以采用两个变量,记录本层应该有多少个节点、和已经遍历到多少个节点。二者相等时,本层节点遍历结束。
// Java代码
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
public class Solution {
public List<List<Integer>> levelOrderBottom(TreeNode root) {
List<List<Integer>> resultList = new ArrayList<>();
// 记录待遍历的节点,每次取出队首元素,并将其子节点(如果有)添加到队列中。
// 当nodeList为空时,所有节点遍历结束
List<TreeNode> nodeList = new ArrayList<>();
// 记录二叉树每一层的节点
List<Integer> layerList = new ArrayList<>();
// 本层应该有多少个节点
int eachLineNodeNum = 1;
// 已经遍历到多少个节点
int currentNodeNum = 0;
// 本层有多少个空节点
int nullNodeNum = 0;
if (root != null)
nodeList.add(root);
while (nodeList.size() != 0) {
TreeNode node = nodeList.remove(0);
if (node == null) {
nullNodeNum ++;
currentNodeNum++;
if (eachLineNodeNum == currentNodeNum) {
// 下一层的节点数应为本层非空节点数 *2
eachLineNodeNum = (eachLineNodeNum - nullNodeNum) * 2;
currentNodeNum = 0;
nullNodeNum = 0;
// System.out.println("一层结束");
// 将layerList复制一份。
// 否则由于"引用传递"的特点,执行layerList.clear()时也会将resultList中的结果清除
if (layerList.size() != 0) {
resultList.add(new ArrayList<Integer>(layerList));
layerList.clear();
}
}
continue;
}
layerList.add(node.val);
currentNodeNum++;
if (eachLineNodeNum == currentNodeNum) {
eachLineNodeNum = (eachLineNodeNum - nullNodeNum) * 2;
currentNodeNum = 0;
nullNodeNum = 0;
// System.out.println("一层结束");
if (layerList.size() != 0) {
resultList.add(new ArrayList<Integer>(layerList));
layerList.clear();
}
}
TreeNode leftNode = node.left;
TreeNode rightNode = node.right;
nodeList.add(leftNode);
nodeList.add(rightNode);
}
Collections.reverse(resultList);
return resultList;
}
}