描述
设计一个算法,判断一颗二叉树是否是完全二叉树。
分析
一颗 k 层 n 个节点的完全二叉树,和 k 层的满二叉树按层序遍历的前 n 个节点形状一致。所以,一颗完全二叉树中的任何节点如果有右儿子,那么一定有左儿子。且层序遍历时,一旦出现空节点,后续节点必定全为空。可以用一个标记标量 mode 记住是否出现过空节点。
步骤
① 初始 mode = 0
② 层序遍历二叉树, mode = 0时:当前节点有左儿子,则左儿子入队。没有左儿子则 mode 变为 1。当前节点有右儿子且 mode = 0,则右儿子入队,如果 mode = 1 则代表不是完全二叉树,返沪 false。如果没有右子,则 mode 变为 1; mode = 1时:如果当前节点有左儿子或右儿子则返回 false。
③ 遍历结束,返回 true
代码
class IsCompleteBinaryTree {
public static boolean isCompleteBinaryTree(Node root) {
byte mode = 0; // 模式0:还未遇到任何 null 节点
Queue<Node> queue = new LinkedList<>();
queue.offer(root); // 根节点入队
while (!queue.isEmpty()) { // 队列为空时循环终止
Node cur = queue.poll(); // 当前节点指向出队节点
if (mode == 0) { // 如果是模式 0
if (cur.left != null) { // 当前节点有左儿子,则左儿子入队
queue.offer(cur.left);
} else {
mode = 1; // 当前节点没有左儿子,遇到空节点,模式转为1
}
if (cur.right != null) { // 如果当前节点有右儿子,但是没有左儿子,则不可能是完全二叉树,直接返回 false
if (mode == 1)
return false;
queue.offer(cur.right); // 反之,右儿子入队列
} else {
mode = 1; // 如果当前节点没有右儿子,模式转为 1
}
} else { // 如果是模式 1,出现任何非空节点,返回 false
if (cur.left != null || cur.right != null) {
return false;
}
}
}
return true;
}
// 节点类
static class Node {
Node left;
Node right;
public int element;
public Node(int element) {
this.element = element;
}
}
public static void main(String[] args) {
// 建树1
Node tree1 = new Node(1);
tree1.left = new Node(2);
tree1.right = new Node(3);
tree1.left.left = new Node(4);
tree1.left.right = new Node(5);
tree1.right.left = new Node(6);
// 判断 tree1 是否是完全二叉树
String rst = isCompleteBinaryTree(tree1) ? "tree1 is complete binary tree" : "tree1 is not complete binary tree";
// 建树2
System.out.println(rst);
Node tree2 = new Node(1);
tree2.left = new Node(2);
tree2.right = new Node(3);
tree2.left.left = new Node(4);
tree2.right.left = new Node(6);
// 判断 tree2 是否是完全二叉树
rst = isCompleteBinaryTree(tree2) ? "tree1 is complete binary tree" : "tree1 is not complete binary tree";
System.out.println(rst);
}
}
out:
tree1 is complete binary tree
tree2 is not complete binary tree