1. import java.util.LinkedList;
    2. /**
    3. * 判断二叉树是否为完全二叉树
    4. */
    5. public class Code01_IsCBT {
    6. public static class Node {
    7. public int value;
    8. public Node left;
    9. public Node right;
    10. public Node(int data) {
    11. this.value = data;
    12. }
    13. }
    14. /**
    15. * 方式1. 基于二叉树按层遍历的基础上
    16. *
    17. * @param head
    18. * @return
    19. */
    20. public static boolean isCBT1(Node head) {
    21. if (head == null) { // 规定,一般情况下,空树为完全二叉树
    22. return true;
    23. }
    24. LinkedList<Node> queue = new LinkedList<>();
    25. // leaf 标识是否遇到过左右两个孩子不双全的节点
    26. boolean leaf = false;
    27. Node l = null;
    28. Node r = null;
    29. queue.add(head);
    30. while (!queue.isEmpty()) {
    31. head = queue.poll();
    32. // 记录当前出队节点的左右孩子
    33. l = head.left;
    34. r = head.right;
    35. // 对遇到的节点进行判断,是否符合完全二叉树的原则
    36. if
    37. (
    38. // 如果遇到了不双全的节点之后,又发现当前节点不是叶节点,(左右孩子任意一个为空则就表示当前节点不是叶子节点)
    39. (leaf && (l != null || r != null))
    40. ||
    41. (l == null && r != null) // 有右无左,
    42. ) {
    43. return false; // 违反以上原则,不是完全二叉树
    44. }
    45. // 不满足上条件,继续按层次遍历
    46. if (l != null) {
    47. queue.add(l);
    48. }
    49. if (r != null) {
    50. queue.add(r);
    51. }
    52. // leaf一旦第一次开启为true,就一直为true。如果第一次遇到左右孩子不是双全的节点,就修改标志为true。以便后续节点的判断
    53. if (l == null || r == null) {
    54. leaf = true;
    55. }
    56. }
    57. // 遍历完没有发现异常节点,返回为true
    58. return true;
    59. }
    60. /**
    61. * 以X为头节点的二叉树是完全二叉树的可能性有以下几种:
    62. * 1. 左满 右满 左高 == 右高
    63. * 2. 左完全 右满 左高 == 右高 + 1
    64. * 3. 左满 右满 左高 == 右高 + 1
    65. * 4. 左满 右完全 左高 == 右高
    66. *
    67. * @param head
    68. * @return
    69. */
    70. public static boolean isCBT2(Node head) {
    71. if (head == null) {
    72. return true;
    73. }
    74. return process(head).isCBT;
    75. }
    76. // 对每一棵子树,是否是满二叉树、是否是完全二叉树、高度
    77. public static class Info {
    78. public boolean isFull; // 是否是满的
    79. public boolean isCBT; // 是否为完全二叉树
    80. public int height; // 树的高度
    81. public Info(boolean full, boolean cbt, int h) {
    82. isFull = full;
    83. isCBT = cbt;
    84. height = h;
    85. }
    86. }
    87. public static Info process(Node X) {
    88. if (X == null) {
    89. return new Info(true, true, 0);
    90. }
    91. Info leftInfo = process(X.left);
    92. Info rightInfo = process(X.right);
    93. // 对于可以处理的Null,以下就可以不必讨论判空的情况。
    94. int height = Math.max(leftInfo.height, rightInfo.height) + 1;
    95. boolean isFull = leftInfo.isFull && rightInfo.isFull && leftInfo.height == rightInfo.height;
    96. boolean isCBT = false;
    97. // 可能性 1. 左满 右满, 左高 == 右高
    98. if (leftInfo.isFull && rightInfo.isFull && leftInfo.height == rightInfo.height) {
    99. isCBT = true;
    100. }
    101. // 可能性2:左完全 右满 , 左高 == 右高 + 1
    102. if (leftInfo.isCBT && rightInfo.isFull && leftInfo.height == rightInfo.height + 1) {
    103. isCBT = true;
    104. }
    105. // 可能性3:左满 右满 左高 == 右高 + 1
    106. if (leftInfo.isFull && rightInfo.isFull && leftInfo.height == rightInfo.height + 1) {
    107. isCBT = true;
    108. }
    109. // 可能性4: 左满 右完全 左高 == 右高
    110. if (leftInfo.isFull && rightInfo.isCBT && leftInfo.height == rightInfo.height) {
    111. isCBT = true;
    112. }
    113. //
    114. // else { // 以x为头整棵树,不满
    115. // if (leftInfo.isCBT && rightInfo.isCBT) {
    116. //
    117. // // 可能性2.
    118. // if (leftInfo.isCBT
    119. // && rightInfo.isFull
    120. // && leftInfo.height == rightInfo.height + 1) {
    121. // isCBT = true;
    122. // }
    123. // if (leftInfo.isFull
    124. // &&
    125. // rightInfo.isFull
    126. // && leftInfo.height == rightInfo.height + 1) {
    127. // isCBT = true;
    128. // }
    129. // if (leftInfo.isFull
    130. // && rightInfo.isCBT && leftInfo.height == rightInfo.height) {
    131. // isCBT = true;
    132. // }
    133. //
    134. //
    135. // }
    136. // }
    137. return new Info(isFull, isCBT, height);
    138. }
    139. // for test
    140. public static Node generateRandomBST(int maxLevel, int maxValue) {
    141. return generate(1, maxLevel, maxValue);
    142. }
    143. // for test
    144. public static Node generate(int level, int maxLevel, int maxValue) {
    145. if (level > maxLevel || Math.random() < 0.5) {
    146. return null;
    147. }
    148. Node head = new Node((int) (Math.random() * maxValue));
    149. head.left = generate(level + 1, maxLevel, maxValue);
    150. head.right = generate(level + 1, maxLevel, maxValue);
    151. return head;
    152. }
    153. public static void main(String[] args) {
    154. int maxLevel = 5;
    155. int maxValue = 100;
    156. int testTimes = 1000000;
    157. for (int i = 0; i < testTimes; i++) {
    158. Node head = generateRandomBST(maxLevel, maxValue);
    159. if (isCBT1(head) != isCBT2(head)) {
    160. System.out.println("Oops!");
    161. }
    162. }
    163. System.out.println("finish!");
    164. }
    165. }