打印函数网上右很多,这里这记录一种,目的是用来调试。
public class PrintBinaryTree {
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int data) {
value = data;
}
}
public static void printTree(Node head) {
System.out.println("Binary Tree:");
printInOrder(head, 0, "H", 17);
System.out.println();
}
public static void printInOrder(Node head, int height, String to, int len) {
if (head == null) {
return;
}
printInOrder(head.right, height + 1, "v", len);
String val = to + head.value + to;
int lenM = val.length();
int lenL = (len - lenM) / 2;
int lenR = len - lenL - lenM;
val = getSpace(lenL) + val + getSpace(lenR);
System.out.println(getSpace(height * len) + val);
printInOrder(head.left, height + 1, "^", len);
}
public static String getSpace(int num) {
String space = " ";
StringBuffer buf = new StringBuffer("");
for (int i = 0; i < num; i++) {
buf.append(space);
}
return buf.toString();
}
}
本质上是是按层遍历二叉树,即依次输出第一层、第二层、…
思想:运用队列,初始时将头节点压入队列;之后每弹出并处理一个节点,就把它的左孩子、右孩子依次压入队列中。
public static void bfsBinaryTree(Node head) {
if (head == null) {
return;
}
Queue<Node> queue = new LinkedList<>();
queue.add(head);
while (!queue.isEmpty()) {
Node cur = queue.poll();
System.out.print(cur.value + " ");
if (cur.left != null) {
queue.add(cur.left);
}
if (cur.right != null) {
queue.add(cur.right);
}
}
}
一棵树的最大宽度是指二叉树上某层包含的最多节点数。
curLevel
、当前层的节点数curLevelNodes
、最大宽度max
。将节点放入队列的同时,在HashMap中存储该节点所在的层数
;弹出节点时,哈希表判断当前节点所在层是否与curLevel
相同,相同则说明该节点属于该层,curLevelNodes++
,不相同则说明该节点不属于该层,已经进入到了下一层,则curLeve++
,同时更新max
。/**
* 使用HashMap求数的最大宽度
*/
public static int treeMaxWidth1(Node head) {
if (head == null) {
return 0;
}
Map<Node, Integer> map = new HashMap<>();
Queue<Node> queue = new LinkedList<>();
int curLevel = 1;
int curLevelNodes = 0;
int max = Integer.MIN_VALUE;
queue.add(head);
map.put(head, curLevel);
while (!queue.isEmpty()) {
Node cur = queue.poll();
if (map.get(cur) == curLevel) {
curLevelNodes++;
} else {
curLevel++;
max = Math.max(max, curLevelNodes);
curLevelNodes = 1;
}
if (cur.left != null) {
map.put(cur.left, curLevel + 1);
queue.add(cur.left);
}
if (cur.right != null) {
map.put(cur.right, curLevel + 1);
queue.add(cur.right);
}
}
return Math.max(max, curLevelNodes);
}
size
,每次内循环都从队列中弹出一个节点进行处理,同时count--
,直到count == 0
本层遍历结束。/**
* 使用count计数每层
*/
public static int treeMaxWidth2(Node head) {
if (head == null) {
return 0;
}
Queue<Node> queue = new LinkedList<>();
int curLevelNodes = 0;
int max = Integer.MIN_VALUE;
queue.add(head);
while (!queue.isEmpty()) {
int count = queue.size();
curLevelNodes = 0;
while (count > 0){
Node cur = queue.poll();
curLevelNodes++;
if (cur.left != null) {
queue.add(cur.left);
}
if (cur.right != null) {
queue.add(cur.right);
}
count--;
}
max = Math.max(max, curLevelNodes);
}
return max;
}
Node curEnd
(当前层最后一个节点),Node nextEnd
(当前队列中最后一个节点),int curLevelNode
(当前层节点数),int max
(最大宽度)root
放入队列中,curEnd = root
,nextEnd = null
,之后每弹出一个节点,就将其左右节点放入队列(如果有的话),同时更新nextEnd
为当前队列中的最后一个节点,然后判断当前节点是否等于curEnd
,如果等于,说明已经到了该层的最后一个节点,此时更新curEnd = nextEnd; nextEnd = null; max = Math.max(curLevelNode, max)
;如果不等于,只更新nextEnd
。重复直到队列为空。/**
* 滚动更新每层的最后一个节点
*/
public static int treeMaxWidth3(Node head) {
if (head == null) {
return 0;
}
Queue<Node> queue = new LinkedList<>();
queue.add(head);
Node curEnd = head;
Node nextEnd = null;
int curLevelNodes = 0;
int max = 0;
while (!queue.isEmpty()) {
Node cur = queue.poll();
curLevelNodes++;
if (cur.left != null) {
queue.add(cur.left);
nextEnd = cur.left;
}
if (cur.right != null) {
queue.add(cur.right);
nextEnd = cur.right;
}
if (curEnd == cur) {
curEnd = nextEnd;
nextEnd = null;
max = Math.max(max, curLevelNodes);
curLevelNodes = 0;
}
}
return max;
}
null
节点也计入该层的宽度。因此我们不能简单的记录每层有多少个节点,而是需要记录每层节点的下标(即把二叉树看做是一个存储在数组中的满二叉树),下标的记录我们可以使用额外的HashMap
来存储,或者直接在队列中存储一个Pair
,这样会快不少。Node
的val
是没有用的,可以直接将下标存储在val
中,但后面就没法复原了,所以刷题时可用,但实际运行效率相比Pair
快了那么一丢丢。left,right
,用于记录每层左右端点的下标。class Solution {
public int widthOfBinaryTree(TreeNode root) {
int max = -1;
int left = 0, right = 0;
Queue<Pair<TreeNode, Integer>> queue = new LinkedList<>();
queue.add(new Pair<TreeNode, Integer>(root, 0));
while (!queue.isEmpty()) {
left = 0;
right = 0;
int count = queue.size();
while (count > 0) {
Pair<TreeNode, Integer> cur = queue.poll();
int index = cur.getValue();
TreeNode curNode = cur.getKey();
if (left == 0) {
left = index;
right = index;
} else {
right = index;
}
if (curNode.left != null) {
queue.add(new Pair<>(curNode.left, 2 * index + 1));
}
if (curNode.right != null) {
queue.add(new Pair<>(curNode.right, 2 * index + 2));
}
count--;
}
max = Math.max(max, right - left + 1);
}
return max;
}
}