import java.util.LinkedList;/** * 判断二叉树是否为完全二叉树 */public class Code01_IsCBT { public static class Node { public int value; public Node left; public Node right; public Node(int data) { this.value = data; } } /** * 方式1. 基于二叉树按层遍历的基础上 * * @param head * @return */ public static boolean isCBT1(Node head) { if (head == null) { // 规定,一般情况下,空树为完全二叉树 return true; } LinkedList<Node> queue = new LinkedList<>(); // leaf 标识是否遇到过左右两个孩子不双全的节点 boolean leaf = false; Node l = null; Node r = null; queue.add(head); while (!queue.isEmpty()) { head = queue.poll(); // 记录当前出队节点的左右孩子 l = head.left; r = head.right; // 对遇到的节点进行判断,是否符合完全二叉树的原则 if ( // 如果遇到了不双全的节点之后,又发现当前节点不是叶节点,(左右孩子任意一个为空则就表示当前节点不是叶子节点) (leaf && (l != null || r != null)) || (l == null && r != null) // 有右无左, ) { return false; // 违反以上原则,不是完全二叉树 } // 不满足上条件,继续按层次遍历 if (l != null) { queue.add(l); } if (r != null) { queue.add(r); } // leaf一旦第一次开启为true,就一直为true。如果第一次遇到左右孩子不是双全的节点,就修改标志为true。以便后续节点的判断 if (l == null || r == null) { leaf = true; } } // 遍历完没有发现异常节点,返回为true return true; } /** * 以X为头节点的二叉树是完全二叉树的可能性有以下几种: * 1. 左满 右满 左高 == 右高 * 2. 左完全 右满 左高 == 右高 + 1 * 3. 左满 右满 左高 == 右高 + 1 * 4. 左满 右完全 左高 == 右高 * * @param head * @return */ public static boolean isCBT2(Node head) { if (head == null) { return true; } return process(head).isCBT; } // 对每一棵子树,是否是满二叉树、是否是完全二叉树、高度 public static class Info { public boolean isFull; // 是否是满的 public boolean isCBT; // 是否为完全二叉树 public int height; // 树的高度 public Info(boolean full, boolean cbt, int h) { isFull = full; isCBT = cbt; height = h; } } public static Info process(Node X) { if (X == null) { return new Info(true, true, 0); } Info leftInfo = process(X.left); Info rightInfo = process(X.right); // 对于可以处理的Null,以下就可以不必讨论判空的情况。 int height = Math.max(leftInfo.height, rightInfo.height) + 1; boolean isFull = leftInfo.isFull && rightInfo.isFull && leftInfo.height == rightInfo.height; boolean isCBT = false; // 可能性 1. 左满 右满, 左高 == 右高 if (leftInfo.isFull && rightInfo.isFull && leftInfo.height == rightInfo.height) { isCBT = true; } // 可能性2:左完全 右满 , 左高 == 右高 + 1 if (leftInfo.isCBT && rightInfo.isFull && leftInfo.height == rightInfo.height + 1) { isCBT = true; } // 可能性3:左满 右满 左高 == 右高 + 1 if (leftInfo.isFull && rightInfo.isFull && leftInfo.height == rightInfo.height + 1) { isCBT = true; } // 可能性4: 左满 右完全 左高 == 右高 if (leftInfo.isFull && rightInfo.isCBT && leftInfo.height == rightInfo.height) { isCBT = true; }//// else { // 以x为头整棵树,不满// if (leftInfo.isCBT && rightInfo.isCBT) {//// // 可能性2.// if (leftInfo.isCBT// && rightInfo.isFull// && leftInfo.height == rightInfo.height + 1) {// isCBT = true;// }// if (leftInfo.isFull// &&// rightInfo.isFull// && leftInfo.height == rightInfo.height + 1) {// isCBT = true;// }// if (leftInfo.isFull// && rightInfo.isCBT && leftInfo.height == rightInfo.height) {// isCBT = true;// }////// }// } return new Info(isFull, isCBT, height); } // for test public static Node generateRandomBST(int maxLevel, int maxValue) { return generate(1, maxLevel, maxValue); } // for test public static Node generate(int level, int maxLevel, int maxValue) { if (level > maxLevel || Math.random() < 0.5) { return null; } Node head = new Node((int) (Math.random() * maxValue)); head.left = generate(level + 1, maxLevel, maxValue); head.right = generate(level + 1, maxLevel, maxValue); return head; } public static void main(String[] args) { int maxLevel = 5; int maxValue = 100; int testTimes = 1000000; for (int i = 0; i < testTimes; i++) { Node head = generateRandomBST(maxLevel, maxValue); if (isCBT1(head) != isCBT2(head)) { System.out.println("Oops!"); } } System.out.println("finish!"); }}