打印二叉树的边界节点有两个标准,这里只看标准一:
1. 头节点为边界节点
2. 叶节点为边界节点
3. 如果节点在其所在的层中是最左或最右的,那么也是边界节点
左程云的《程序员代码面试指南》里面的解法如下:
1. 递归遍历树,找到树的最大高度,然后定义保存每层最左最右边界节点的二维数组
2. 递归找出每层最左最右边界节点(如果该层只有一个节点,那么会重复保存)
3. 先从上往下打印左边界节点,然后递归找到每层的叶子节点并打印,最后从下往上打印最右边界节点
代码上递归用的比较多,而且要好几次DFS遍历树,我给出的解法做了一点优化:
1. 使用一次BFS层遍历树,就可以找出所有需要的节点
2. 不用计算树的高度,并且无递归代码
算法代码如下:
public void printEdgeNodes(TreeNode head){
Deque<TreeNode> q = new LinkedList<>();
List<TreeNode> lefts = new ArrayList<>(); // 保存最左边界节点
Stack<TreeNode> rights = new Stack<>(); // 保存最右边界节点,因为是从下往上打印,所以用栈
List<TreeNode> leafs = new ArrayList<>(); // 保存每层的叶子节点
q.addLast(head); // 预先放入头节点
while (!q.isEmpty()){
int size = q.size();
for (int i = 0; i < size; i++){
TreeNode cur = q.removeFirst();
// if - else 保证节点不会重复出现在不同集合里
if (i == 0){
lefts.add(cur);
} else if (i == size - 1){
rights.push(cur);
} else if (cur.left == null && cur.right == null){
leafs.add(cur);
}
// 添加当前节点的左右节点到队列
if (cur.left != null)
q.addLast(cur.left);
if (cur.right != null)
q.addLast(cur.right);
}
}
// 先打印左边界
for (TreeNode cur : lefts){
System.out.println(cur.value);
}
// 再打印叶子节点
for (TreeNode cur : leafs){
System.out.println(cur.value);
}
// 最后打印有边界
while (!rights.isEmpty()){
System.out.println(rights.pop().value);
}
}