5.2 二叉树的概念
5、最近公共节点
public static int 最近公共先祖(int x, int y) {
if (x == 0 || y == 0) return 0;
int flags;
/* 計算出x和y具體在第幾層,原理類似於子網掩碼 */
for (flags = 1; (x & flags) != x && (y & flags) != y; flags <<= 1, flags++);
while ((x & flags) != x) x >>= 1;
while ((y & flags) != y) y >>= 1;
for (; x != y; x >>>= 1, y >>>= 1);
return x;
}
我感觉我写的这个算法效率是真的高。
打脸来得真快,跟答案相比我这个就是个屎。如下:
public static int 最近公共先祖(int x, int y) {
if (x <= 0 || y <= 0) {
throw new IllegalArgumentException("傳參必須是正數!");
}
while (x != y) {
if (x > y) {
x >>>= 1;
} else {
y >>>= 1;
}
}
return x;
}
线索二叉树与二叉树的遍历
先写个二叉树:
class 二叉樹節點 {
int 值;
二叉樹節點 左;
二叉樹節點 右;
@Override
public String toString() {
return "" + 值;
}
public 二叉樹節點(int val) {
this.值 = val;
}
public 二叉樹節點(int 值, 二叉樹節點 左, 二叉樹節點 右) {
this.值 = 值;
this.左 = 左;
this.右 = 右;
}
public 二叉樹節點(Integer[] 數組) {
int 指針 = 0;
if (數組[0] == null) throw new IllegalArgumentException();
this.值 = 數組[指針];
Queue<二叉樹節點> 隊列 = new LinkedList<>();
隊列.offer(this);
while (!隊列.isEmpty()) {
int 總數 = 隊列.size();
while (總數 > 0) {
二叉樹節點 節點 = 隊列.poll();
總數--;
指針++;
if (指針 >= 數組.length) return;
if (數組[指針] != null) {
節點.左 = new 二叉樹節點(數組[指針]);
隊列.add(節點.左);
}
指針++;
if (指針 >= 數組.length) return;
if (數組[指針] != null) {
節點.右 = new 二叉樹節點(數組[指針]);
隊列.add(節點.右);
}
}
}
}
}
3、用栈实现二叉树的后序遍历
public static String 後序遍歷(二叉樹節點 節點) {
StringBuilder 串 = new StringBuilder();
Stack<二叉樹節點> 棧 = new Stack<>();
二叉樹節點 前驅 = null;
while (節點 != null || !棧.isEmpty()) {
while(節點 != null) {
棧.push(節點);
節點 = 節點.左;
}
節點 = 棧.peek();
if (節點.右 == null || 節點.右 == 前驅) {
串.append(節點.值).append(' ');
棧.pop();
前驅 = 節點;
節點 = null;
} else {
節點 = 節點.右;
}
}
return 串.toString();
}
答案跟这个差不多。
4、自下而上、从右到左的层序遍历
public static String 自下而上從右到左層序遍歷(二叉樹節點 節點) {
if (節點 == null) return "";
StringBuilder 串 = new StringBuilder();
Stack<StringBuilder> 棧 = new Stack<>();
Queue<二叉樹節點> 隊列 = new LinkedList<>();
隊列.offer(節點);
棧.push(new StringBuilder().append(節點.值).append(' '));
while (!隊列.isEmpty()) {
StringBuilder 臨時串 = new StringBuilder();
int 總數 = 隊列.size();
while (總數 > 0) {
二叉樹節點 臨時節點 = 隊列.poll();
if (臨時節點.右 != null) {
臨時串.append(臨時節點.右);
隊列.offer(臨時節點.右);
}
if (臨時節點.左 != null) {
臨時串.append(臨時節點.左);
隊列.offer(臨時節點.左);
}
總數--;
}
if (臨時串.length() > 0) {
棧.push(臨時串);
}
}
while (!棧.isEmpty()) {
串.append(棧.pop()).append('\n');
}
return 串.toString();
}
5、非递归求二叉树高度
坏得很啊,这非递归该咋写。
麻麻的,我愣是写不出来。
看了下答案上的提示,层序遍历,沃靠,豁然开朗,开写。
public static int 非遞歸求二叉樹高度(二叉樹節點 節點) {
int 答案 = 0;
Queue<二叉樹節點> 隊 = new LinkedList<>();
隊.offer(節點);
while (!隊.isEmpty()) {
int 總數 = 隊.size();
答案++;
while (總數 > 0) {
二叉樹節點 臨時節點 = 隊.poll();
if (臨時節點.左 != null) {
隊.offer(臨時節點.左);
}
if (臨時節點.右 != null) {
隊.offer(臨時節點.右);
}
總數--;
}
}
return 答案;
}
6、由先序遍历和中序遍历获得二叉树
private static int[] 先序;
private static int[] 中序;
public static 二叉樹節點 由先序中序獲得二叉樹(int[] 先序, int[] 中序) {
if (先序.length != 中序.length) throw new IllegalArgumentException();
if (先序.length == 0) return null;
二叉樹節點.先序 = 先序;
二叉樹節點.中序 = 中序;
return 由先序中序獲得二叉樹(0, 先序.length, 0, 中序.length);
}
private static 二叉樹節點 由先序中序獲得二叉樹(int 先序始, int 先序長, int 中序始, int 中序長) {
int 值 = 先序[先序始];
if (先序長 == 1 && 中序長 == 1) {
if (先序[先序始] == 中序[中序始]) {
return new 二叉樹節點(值);
} else {
throw new IllegalArgumentException();
}
}
int 指針;
boolean 找到否 = false;
for (指針 = 0; 指針 < 中序長; 指針++) {
if (值 == 中序[中序始 + 指針]) {
找到否 = true;
break;
}
}
if (!找到否) throw new IllegalArgumentException();
return new 二叉樹節點(值,
由先序中序獲得二叉樹(先序始 + 1, 指針, 中序始, 指針),
由先序中序獲得二叉樹(先序始 + 1 + 指針, 先序長 - 1 - 指針, 中序始 + 指針 + 1, 中序長 - 1 - 指針));
}
7、判断是否为完全二叉树
家人们,我哭了,你们呢 😭
这就完全不会啊。
首先呢,这玩意必然是层序,先写着看吧。
public static boolean 是完全二叉樹(二叉樹節點 節點) {
if (節點 == null) return true;
Queue<二叉樹節點> 隊 = new LinkedList<>();
隊.offer(節點);
while (!隊.isEmpty()) {
boolean 旗幟 = false;
int 總數 = 隊.size();
while (總數 > 0) {
二叉樹節點 臨時節點 = 隊.poll();
if (臨時節點.左 != null) {
if (旗幟) return false;
隊.offer(臨時節點.左);
} else {
if (!旗幟) 旗幟 = true;
}
if (臨時節點.右 != null) {
if (旗幟) return false;
隊.offer(臨時節點.右);
} else {
if (!旗幟) 旗幟 = true;
}
總數--;
}
}
return true;
}
8、分支节点个数
public static int 分支節點個數(二叉樹節點 節點) {
if (節點 == null || (節點.左 == null && 節點.右 == null)) return 0;
return 1 + 分支節點個數(節點.左) + 分支節點個數(節點.右);
}
9、交换左右子树节点
public static 二叉樹節點 交換左右子樹(二叉樹節點 節點) {
if (節點 == null) return null;
二叉樹節點 臨時節點 = 節點.左;
節點.左 = 交換左右子樹(節點.右);
節點.右 = 交換左右子樹(臨時節點);
return 節點;
}
后面这几个题简单的没亩。