判斷二叉樹是否為滿二叉樹
作者:Grey
原文地址:
滿二叉樹定義
一個二叉樹,如果每一個層的結點數都達到最大值,則這個二叉樹就是滿二叉樹。也就是說,如果一個二叉樹的層數為K,且結點總數是
(2^k) -1
,則它就是滿二叉樹。
方法1
使用公式,求二叉樹的層數 k, 結點數 n,如果滿足(2^k) -1 = n
,則為滿二叉樹。
定義資料結構
public static class Info1 {
public int height;
public int nodes;
public Info1(int h, int n) {
height = h;
nodes = n;
}
}
其中height
表示二叉樹的層數,nodes
表示二叉樹的結點個數。
定義遞迴函式
Info1 process1(Node head)
遞迴含義是:head 為頭的二叉樹的層數和點數都是多少,接下來就是 base case
即:head == null
的時候,此時,height == 0
且 nodes == 0
if (head == null) {
return new Info1(0, 0);
}
接下來是普遍情況
// 去左樹上收集資訊
Info1 leftInfo = process1(head.left);
// 去右樹上收集資訊
Info1 rightInfo = process1(head.right);
// 整合成 head 自己的資訊
int height = Math.max(leftInfo.height, rightInfo.height) + 1;
int nodes = leftInfo.nodes + rightInfo.nodes + 1;
return new Info1(height, nodes);
方法2
定義如下資料結構
public static class Info2 {
public boolean isFull;
public int height;
public Info2(boolean f, int h) {
isFull = f;
height = h;
}
}
其中isFull
表示是否為滿二叉樹,height
表示二叉樹的高度。
定義了這個資料結構後,可以梳理可能性,如果以 head
為頭的樹要符合滿二叉樹。則需要同時滿足下面三種情況
情況1:左樹是滿二叉樹
情況2:右樹是滿二叉樹;
情況3:左右樹的高度一樣。
定義遞迴函式
Info2 process2(Node head)
遞迴含義就是返回以head
為頭的二叉樹Info2
結構資訊。
base case是
if (h == null) {
return new Info2(true, 0);
}
h == null
預設是滿二叉樹,結點個數為0。
接下來是普遍情況,即去左右子樹收集相關資訊,整合成以h
為頭二叉樹的資訊。
// 去左子樹收集相關資訊
Info2 leftInfo = process2(h.left);
// 去右子樹收集相關資訊
Info2 rightInfo = process2(h.right);
// 整合成 h 自己的新
boolean isFull = leftInfo.isFull && rightInfo.isFull && leftInfo.height == rightInfo.height;
int height = Math.max(leftInfo.height, rightInfo.height) + 1;
return new Info2(isFull, height);
方法1 和 方法2 的時間複雜度都是O(n)
,即經過一次後序遍歷的時間複雜度。
兩種解法的完整程式碼(含測試程式碼)如下
public class Code_IsFull {
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int data) {
this.value = data;
}
}
// 第一種方法
// 收集整棵樹的高度h,和節點數n
// 只有滿二叉樹滿足 : 2 ^ h - 1 == n
public static boolean isFull1(Node head) {
if (head == null) {
return true;
}
Info1 all = process1(head);
return (1 << all.height) - 1 == all.nodes;
}
public static class Info1 {
public int height;
public int nodes;
public Info1(int h, int n) {
height = h;
nodes = n;
}
}
public static Info1 process1(Node head) {
if (head == null) {
return new Info1(0, 0);
}
Info1 leftInfo = process1(head.left);
Info1 rightInfo = process1(head.right);
int height = Math.max(leftInfo.height, rightInfo.height) + 1;
int nodes = leftInfo.nodes + rightInfo.nodes + 1;
return new Info1(height, nodes);
}
// 第二種方法
// 收集子樹是否是滿二叉樹
// 收集子樹的高度
// 左樹滿 && 右樹滿 && 左右樹高度一樣 -> 整棵樹是滿的
public static boolean isFull2(Node head) {
if (head == null) {
return true;
}
return process2(head).isFull;
}
public static class Info2 {
public boolean isFull;
public int height;
public Info2(boolean f, int h) {
isFull = f;
height = h;
}
}
public static Info2 process2(Node h) {
if (h == null) {
return new Info2(true, 0);
}
Info2 leftInfo = process2(h.left);
Info2 rightInfo = process2(h.right);
boolean isFull = leftInfo.isFull && rightInfo.isFull && leftInfo.height == rightInfo.height;
int height = Math.max(leftInfo.height, rightInfo.height) + 1;
return new Info2(isFull, 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;
System.out.println("測試開始");
for (int i = 0; i < testTimes; i++) {
Node head = generateRandomBST(maxLevel, maxValue);
if (isFull1(head) != isFull2(head)) {
System.out.println("出錯了!");
}
}
System.out.println("測試結束");
}
}