二叉树不能形成环
- 先序、中序、后序遍历
先序:对任意一个子树的处理顺序,都是先头结点、再左子树、再右子树
中序:左头右
后序:左右头
[image:710374ED-4483-43C6-8740-52B0AB1597BA-22873-00006BA364335C85/iShot2020-12-18 20.40.44.png] - 非递归方式实现二叉树的先序、中序、后序
- 任何递归函数都可以改成非递归
- 自己设计压栈的来实现
- 先序实现逻辑:
- 放入head
- 循环(如果栈不为空)
- 出栈为head
- 打印head
- 如果有右,压入右
- 如果有左,压入左
- 后序的实现逻辑:后序等于头右左的倒叙 -> 准备两个栈,head出栈的时候不直接打印,而是放入第二个栈
- 放入head
- 循环(stack1不为空)
- 如果有左,压入s1
- 如果有右,压入s1
- 循环(stack2不为空)
- 打印
- 中序的实现逻辑:
- 整条左边界依次入栈
- 弹出节点并打印,来到右树执行逻辑1
- 一个栈实现后序遍历(跳过)
- 先序实现逻辑:
- 实现二叉树的按层遍历
- 其实就是宽度优先遍历,用 队列
- 可以通过设置flag变量的方式, 来发现某一层的结束
public static void level(Node head) {
if (head == null) {
return;
}
Queue<Node> queue = new LinkedList<>();
queue.add(head);
while (!queue.isEmpty()) {
Node cur = queue.poll();
System.out.println(cur.value);
if (cur.left != null) {
queue.add(cur.left);
}
if (cur.right != null) {
queue.add(cur.right);
}
}
}
- 统计二叉树最宽的一行的宽度
- 方法一【使用map】:使用一个Map<Node, height> levelMap来记录每个节点所对应的高度
public static int maxWidthUseMap(Node head) {
if (head == null) {
return 0;
}
Queue<Node> queue = new LinkedList<>();
queue.add(head);
// key 在 哪一层,value
HashMap<Node, Integer> levelMap = new HashMap<>();
levelMap.put(head, 1);
int curLevel = 1; // 当前你正在统计哪一层的宽度
int curLevelNodes = 0; // 当前层curLevel层,宽度目前是多少
int max = 0;
while (!queue.isEmpty()) {
Node cur = queue.poll();
int curNodeLevel = levelMap.get(cur);
if (cur.left != null) {
levelMap.put(cur.left, curNodeLevel + 1);
queue.add(cur.left);
}
if (cur.right != null) {
levelMap.put(cur.right, curNodeLevel + 1);
queue.add(cur.right);
}
if (curNodeLevel == curLevel) {
curLevelNodes++;
} else {
max = Math.max(max, curLevelNodes);
curLevel++;
curLevelNodes = 1;
}
}
max = Math.max(max, curLevelNodes);
return max;
}
2. 方法二:其实并不在乎第几层,只在乎每行什么时候结束
- Node nextEnd用来在循环本层的时候记录下一层的最右节点
- Node curEnd用来记录在本层的最右节点,当cur = curEnd的时候进行当层节点的结算,准备进入下一层
1. max = Math.max(max, curLevelNodes)
2. curLevelNodes = 0
3. curEnd = nextEnd 指向下一个最后节点
public static int maxWidthNoMap(Node head) {
if (head == null) {
return 0;
}
Queue<Node> queue = new LinkedList<>();
queue.add(head);
Node curEnd = head; // 当前层,最右节点是谁
Node nextEnd = null; // 下一层,最右节点是谁
int max = 0;
int curLevelNodes = 0; // 当前层的节点数
while (!queue.isEmpty()) {
Node cur = queue.poll();
if (cur.left != null) {
queue.add(cur.left);
nextEnd = cur.left;
}
if (cur.right != null) {
queue.add(cur.right);
nextEnd = cur.right;
}
curLevelNodes++;
if (cur == curEnd) {
max = Math.max(max, curLevelNodes);
curLevelNodes = 0;
curEnd = nextEnd;
}
}
return max;
}
- 二叉树的序列化和反序列化【不要忽略Null节点】
- 可以用先序或者中序或者后序或者按层遍历,来实现二叉树的序列化
- 用了什么方式序列化,就用什么方式反序列化
序列化
[image:4A49A2BC-1482-4ADC-B71D-461396CAF695-22873-00007B1F849017C5/iShot2020-12-19 10.19.36.png]
- 先序:
public static void pres(Node head, Queue<String> ans) {
if (head == null) {
ans.add(null);
} else {
ans.add(String.valueOf(head.value));
pres(head.left, ans);
pres(head.right, ans);
}
}
- 按层
public static Queue<String> levelSerial(Node head) {
Queue<String> ans = new LinkedList<>();
if (head == null) {
ans.add(null);
} else {
ans.add(String.valueOf(head.value));
Queue<Node> queue = new LinkedList<Node>();
queue.add(head);
while (!queue.isEmpty()) {
head = queue.poll(); // head 父 子
if (head.left != null) {
ans.add(String.valueOf(head.left.value));
queue.add(head.left);
} else {
ans.add(null);
}
if (head.right != null) {
ans.add(String.valueOf(head.right.value));
queue.add(head.right);
} else {
ans.add(null);
}
}
}
return ans;
}