0%

二叉树

二叉树相关知识点及题目。

实现二叉树的先序,中序,后序遍历,包括递归方式和非递归方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
import java.util.Stack;
public class Code_01_PreInPosTraversal {
public static class Node {
public int value;
public Node left;
public Node right;

public Node(int data) {
this.value = data;
}
}

public static void preOrderRecur(Node head) {
if (head == null) {
return;
}
System.out.print(head.value + " ");
preOrderRecur(head.left);
preOrderRecur(head.right);
}

public static void inOrderRecur(Node head) {
if (head == null) {
return;
}
inOrderRecur(head.left);
System.out.print(head.value + " ");
inOrderRecur(head.right);
}

public static void posOrderRecur(Node head) {
if (head == null) {
return;
}
posOrderRecur(head.left);
posOrderRecur(head.right);
System.out.print(head.value + " ");
}

public static void preOrderUnRecur(Node head){
System.out.print("pre-order: ");
if(head != null){
Stack<Node> stack = new Stack<Node>();
stack.add(head);
while (!stack.isEmpty()){
head =stack.pop();
System.out.print(head.value+" ");
if(head.right!=null){
stack.push(head.right);
}
if(head.left!=null){
stack.push(head.left);
}
}
}
System.out.println();
}
public static void inOrderUnRecur(Node head){
System.out.print("in-order: ");
if(head!=null){
Stack<Node> stack = new Stack<Node>();
while (!stack.isEmpty() || head!=null){
if(head!=null){
stack.push(head);
head = head.left;
}else {
head = stack.pop();
System.out.print(head.value + " ");
head = head.right;
}
}
}
System.out.println();
}

public static void posOrderUnRecur1(Node head){
System.out.print("pos-order: ");
Stack<Node> s1 = new Stack<Node>();
Stack<Node> s2 = new Stack<Node>();
s1.push(head);
while (!s1.isEmpty()){
head = s1.pop();
s2.push(head);
if(head.left !=null){
s1.push(head.left);
}
if(head.right!=null){
s1.push(head.right);
}
}
while (!s2.isEmpty()){
System.out.print(s2.pop().value + " ");
}
System.out.println();
}

public static void posOrderUnRecur2(Node h) {
System.out.print("pos-order: ");
if (h != null) {
Stack<Node> stack = new Stack<Node>();
stack.push(h);
Node c = null;
while (!stack.isEmpty()) {
c = stack.peek();
if (c.left != null && h != c.left && h != c.right) {
stack.push(c.left);
} else if (c.right != null && h != c.right) {
stack.push(c.right);
} else {
System.out.print(stack.pop().value + " ");
h = c;
}
}
}
System.out.println();
}
}

如何直观的打印一颗二叉树

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class Code_02_PrintBinaryTree {
public static class Node {
public int value;
public Node left;
public Node right;

public Node(int data) {
this.value = data;
}
}

public static void printTree(Node head) {
System.out.println("Binary Tree:");
printInOrder(head, 0, "H", 17);
System.out.println();
}

public static void printInOrder(Node head, int height, String to, int len) {
if (head == null) {
return;
}
printInOrder(head.right, height + 1, "v", len);
String val = to + head.value + to;
int lenM = val.length();
int lenL = (len - lenM) / 2;
int lenR = len - lenM - lenL;
val = getSpace(lenL) + val + getSpace(lenR);
System.out.println(getSpace(height * len) + val);
printInOrder(head.left, height + 1, "^", len);
}

public static String getSpace(int num) {
String space = " ";
StringBuffer buf = new StringBuffer("");
for (int i = 0; i < num; i++) {
buf.append(space);
}
return buf.toString();
}
}

在二叉树中找到一个节点的后继节点

image-20201026155608229

  • 找前驱也类似。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class Code_03_SuccessorNode {
public static class Node {
public int value;
public Node left;
public Node right;
public Node parent;

public Node(int data) {
this.value = data;
}
}

public static Node getSuccessorNode(Node node) {
if (node == null) {
return node;
}
if (node.right != null) {
return getLeftMost(node.right);
} else {
Node parent = node.parent;
while (parent != null && parent.left != node) {
node = node.parent;
parent = node.parent;
}
return parent;
}
}

public static Node getLeftMost(Node node) {
if (node == null) {
return node;
}
while (node.left != null) {
node = node.left;
}
return node;
}
}

介绍二叉树的序列化和反序列化

  • 先序,中序,后序 序列化
  • 层次序列化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
import java.util.LinkedList;
import java.util.Queue;

public class Code_04_SerializeAndReconstructTree {
public static class Node {
public int value;
public Node left;
public Node right;

public Node(int data) {
this.value = data;
}
}

public static String serialByPre(Node head) {
if (head == null) {
return "#!";
}
String res = head.value + "!";
res += serialByPre(head.left);
res += serialByPre(head.right);
return res;
}

public static Node reconByPreString(String preStr) {
String[] values = preStr.split("!");
Queue<String> queue = new LinkedList<String>();
for (int i = 0; i < values.length; i++) {
queue.offer(values[i]);
}
return reconPreOrder(queue);
}

public static Node reconPreOrder(Queue<String> queue) {
String value = queue.poll();
if (value.equals("#")) {
return null;
}
Node head = new Node(Integer.valueOf(value));
head.left = reconPreOrder(queue);
head.right = reconPreOrder(queue);
return head;
}

public static String serialByLevel(Node head) {
if (head == null) {
return "#!";
}
String res = head.value + "!";
Queue<Node> queue = new LinkedList<Node>();
queue.offer(head);
while (!queue.isEmpty()) {
head = queue.poll();
if (head.left != null) {
res += head.left.value + "!";
queue.offer(head.left);
} else {
res += "#!";
}
if (head.right != null) {
res += head.right.value + "!";
queue.offer(head.right);
} else {
res += "#!";
}
}
return res;
}

public static Node reconByLevelString(String levelStr) {
String[] values = levelStr.split("!");
int index = 0;
Node head = generateNodeByString(values[index++]);
Queue<Node> queue = new LinkedList<Node>();
if (head != null) {
queue.offer(head);
}
Node node = null;
while (!queue.isEmpty()) {
node = queue.poll();
node.left = generateNodeByString(values[index++]);
node.right = generateNodeByString(values[index++]);
if (node.left != null) {
queue.offer(node.left);
}
if (node.right != null) {
queue.offer(node.right);
}
}
return head;
}

public static Node generateNodeByString(String val) {
if (val.equals("#")) {
return null;
}
return new Node(Integer.valueOf(val));
}
}

折纸问题

image-20201026155646787

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Code_05_PaperFolding {

public static void printAllFolds(int N) {
printProcess(1, N, true);
}

public static void printProcess(int i, int N, boolean down) {
if (i > N) {
return;
}
printProcess(i + 1, N, true);
System.out.println(down ? "down" : "up");
printProcess(i + 1, N, false);
}

public static void main(String[] args) {
int N = 4;
printAllFolds(N);
}
}

判断一棵二叉树是否是平衡二叉树

  • 平衡二叉树:对于树中任意一个节点,它的左子树右子树高度差不超过1.

  • 递归套路

  • 平衡性用来解决效率问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
public class Code_06_IsBalancedTree {
public static class Node {
public int value;
public Node left;
public Node right;

public Node(int data) {
this.value = data;
}
}
//递归套路
public static class ReturnData {
public boolean isB;
public int h;

public ReturnData(boolean isB, int h) {
this.isB = isB;
this.h = h;
}
}

public static boolean isB(Node head) {
return process(head).isB;
}

public static ReturnData process(Node head) {
if (head == null) {
return new ReturnData(true, 0);
}
ReturnData leftData = process(head.left);
if (!leftData.isB) {
return new ReturnData(false, 0);
}
ReturnData rightData = process(head.right);
if (!rightData.isB) {
return new ReturnData(false, 0);
}
if (Math.abs(leftData.h - rightData.h) > 1) {
return new ReturnData(false, 0);
}
return new ReturnData(true, Math.max(leftData.h, rightData.h) + 1);
}
//方法2
public static boolean isBalance(Node head) {
boolean[] res = new boolean[1];
res[0] = true;
getHeight(head, 1, res);
return res[0];
}

public static int getHeight(Node head, int level, boolean[] res) {
if (head == null) {
return level;
}
int lH = getHeight(head.left, level + 1, res);
if (!res[0]) {
return level;
}
int rH = getHeight(head.right, level + 1, res);
if (!res[0]) {
return level;
}
if (Math.abs(lH - rH) > 1) {
res[0] = false;
}
return Math.max(lH, rH);
}
}

判断一棵树是否是搜索二叉树、判断一棵树是否是完全二叉树

  • 搜索二叉树:对于任意一个节点,左子树都比它小,右子树都比它大(通常不出现重复节点)——中序遍历是升序的,就是搜索二叉树,否则就不是
  • 完全二叉树判断——二叉树按层遍历:1,如果一个节点有右孩子但没有左孩子,返回false;2,如果一个节点不是左右两个孩子都全(有左没右,或者左右都没有),后面遇到的所有节点都必须是叶节点,否则不是完全二叉树
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;

public class Code_07_IsBSTAndCBT {
public static class Node {
public int value;
public Node left;
public Node right;

public Node(int data) {
this.value = data;
}
}

// 中序遍历非递归
public static boolean isBST_InOrder_UnCur(Node head) {
if (head != null) {
int num = Integer.MIN_VALUE;
Stack<Node> stack = new Stack<Node>();
while (head != null || !stack.isEmpty()) {
if (head != null) {
stack.push(head);
head = head.left;
} else {
head = stack.pop();
if (head.value < num) {
return false;
}
num = head.value;
head = head.right;
}
}
}
return true;
}

public static boolean isBST(Node head) {
if (head == null) {
return true;
}
boolean res = true;
Node pre = null;
Node cur1 = head;
Node cur2 = null;
while (cur1 != null) {
cur2 = cur1.left;
if (cur2 != null) {
while (cur2.right != null && cur2.right != cur1) {
cur2 = cur2.right;
}
if (cur2.right == null) {
cur2.right = cur1;
cur1 = cur1.left;
continue;
} else {
cur2.right = null;
}
}
if (pre != null && pre.value > cur1.value) {
res = false;
}
pre = cur1;
cur1 = cur1.right;
}
return res;
}

public static boolean isCBT(Node head) {
if (head == null) {
return true;
}
Queue<Node> queue = new LinkedList<Node>();
boolean leaf = false;
Node l = null;
Node r = null;
queue.offer(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.offer(l);
}
if (r != null) {
queue.offer(r);
} else {
leaf = true;
}
}
return true;
}
}

已知一棵完全二叉树,求其节点的个数

image-20201026155813142

  • 满二叉树:N = 2^l -1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class Code_08_CompleteTreeNodeNumber {
public static class Node {
public int value;
public Node left;
public Node right;

public Node(int data) {
this.value = data;
}
}

public static int nodeNum(Node head) {
if (head == null) {
return 0;
}
return bs(head, 1, mostLeftLevel(head, 1));
}

public static int bs(Node node, int level, int h) {
if (level == h) {
return 1;
}
if (mostLeftLevel(node.right, level + 1) == h) {
return (1 << (h - level)) + bs(node.right, level + 1, h);
} else {
return (1 << (h - level - 1)) + bs(node.left, level + 1, h);
}
}

public static int mostLeftLevel(Node node, int level) {
while (node != null) {
level++;
node = node.left;
}
return level - 1;
}
}

时间复杂度:O((logN)^2) 遍历节点数logN,每个节点求边界,logN