-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathBinarySearchTree.java
277 lines (256 loc) · 8.97 KB
/
BinarySearchTree.java
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
package ds.bst.base;
/**
* 二叉查找树的插入、遍历、查找、删除
*
* @author yangyi 2019年01月05日00:15:27
*/
public class BinarySearchTree {
/**
* 二叉查找树的根
*/
private TreeNode root;
public static class TreeNode {
public int value;
public TreeNode left;
public TreeNode right;
public TreeNode(int value) {
this.value = value;
}
}
/**
* 二叉查找树的插入操作
*
* @param value 插入的对象
* @return 返回这颗树
*/
public TreeNode insert(int value) {
//如果这个二叉查找树是null,就说明进来的value是第一个元素,即将作为此棵树的根
if (root == null) {
root = new TreeNode(value);
return root;
}
//这里的p起一个指示作用,用来标记你现在走到整棵树的哪个节点了
TreeNode p = root;
//死循环去找地方,直到成功找到属于自己的位置后return
while (true) {
//如果被插的是一棵已经存在的树,判断value的大小,小往左找插入的地方,大往右找插入的地方
if (p.value > value) {
//为null时说明找到地方了,开插
if (p.left == null) {
p.left = new TreeNode(value);
//warning:这里返回千万不能是p,p只是你当前节点的位置,此处应该返回整棵树,即root
return root;
}
p = p.left;
} else {
//为null时说明找到地方了,开插
if (p.right == null) {
p.right = new TreeNode(value);
//warning:这里返回千万不能是p,p只是你当前节点的位置,此处应该返回整棵树,即root
return root;
}
p = p.right;
}
}
}
/**
* 前序遍历
*
* @param root 要遍历的对象
*/
public void prePrintTree(TreeNode root) {
if (root == null) {
return;
}
System.out.println(root.value);
prePrintTree(root.left);
prePrintTree(root.right);
}
/**
* 中序遍历
*
* @param root 要遍历的对象
*/
public void inPrintTree(TreeNode root) {
if (root == null) {
return;
}
inPrintTree(root.left);
System.out.println(root.value);
inPrintTree(root.right);
}
/**
* 后序遍历
*
* @param root 要遍历的对象
*/
public void postPrintTree(TreeNode root) {
if (root == null) {
return;
}
postPrintTree(root.left);
postPrintTree(root.right);
System.out.println(root.value);
}
/**
* 逆序遍历
*
* @param root 要遍历的对象
*/
public void reversePrintTree(TreeNode root) {
if (root == null) {
return;
}
reversePrintTree(root.right);
System.out.println(root.value);
reversePrintTree(root.left);
}
/**
* 查找节点
*
* @param value 要查找的值
* @return 所在的节点
*/
public TreeNode find(int value) {
TreeNode p = root;
while (p != null) {
if (value < p.value) {
p = p.left;
} else if (value > p.value) {
p = p.right;
} else {
return p;
}
}
return null;
}
/**
* 删除节点:(分3种情况)
* 情况1: 如果要删除的节点没有子节点,只需要将被删除的节点的父节点指向被删除节点自己的指针置为null
* 情况2: 如果要删除的节点只有一个子节点(只有左子节点或者右子节点),只需要令被删除节点的父节点指向被删除节点的子节点
* 情况3: 如果要删除的节点有两个子节点,需要找到这个被删除节点的右子树中的最小节点,将这个最小节点替换到要删除的节点上,然后删除掉这个最小节点(即令最小节点的父节点指向null)
*
* @param value 要删除的值
*/
public void delete(int value) {
//初始化两个指示器,p指示删除的节点,从根部开始,pp是指示器p的父节点
TreeNode p = root;
TreeNode pp = null;
//如果没有遇到要删除的节点的值value,继续往下走
while (p != null && p.value != value) {
pp = p;
if (p.value > value) {
p = p.left;
} else {
p = p.right;
}
}
//不存在可以删除的东西,直接返回
if (p == null) {
return;
}
//情况1:删除有两个子节点的节点,即左右子节点都不为null
if (p.left != null && p.right != null) {
//需要找到被删除节点p的右子树中的最小节点
//初始化最小的节点
TreeNode minp = p.right;
//初始化最小节点的父节点
TreeNode minpp = p;
//提到了最小节点,肯定是往左子树中找,如果左子节点不为null就往下继续找
while (minp.left != null) {
minpp = minp;
minp = minp.left;
}
//循环结束说明找到要删除的节点了,开始着手删除
//目前已经找到了要删除的节点p和p的右子树的最小节点minp
p.value = minp.value;
//删除的节点p用最小节点minp填补
p = minp;
pp = minpp;
}
//情况2:删除的是叶子节点 或者 删除的是一条腿的节点,即只有一个左子树或者右子树
//删除节点p的子节点
TreeNode child;
if (p.left != null) {
child = p.left;
} else if (p.right != null) {
child = p.right;
} else {
//左右节点都为null,意味着子节点也为null,也就是所谓的叶子节点
child = null;
}
if (pp == null) {
root = child;
} else if (pp.left == p) {
pp.left = child;
} else {
pp.right = child;
}
}
/**
* 反转一颗二叉树
*/
private TreeNode reverseTree(TreeNode tree) {
if (tree == null) {
return null;
}
tree.left = reverseTree(tree.left);
tree.right = reverseTree(tree.right);
TreeNode temp = tree.left;
tree.left = tree.right;
tree.right = temp;
return tree;
}
public static void main(String[] args) {
int[] ints = new int[10];
System.out.println("准备一个数组用来构建树,并且输出来看看:");
for (int i = 0; i < ints.length; i++) {
int num = (int) (Math.random() * 10);
ints[i] = num;
System.out.println(ints[i]);
}
BinarySearchTree binarySearchTree = new BinarySearchTree();
System.out.println("用这个数组来构建树↓");
TreeNode tree = null;
for (int anInt : ints) {
tree = binarySearchTree.insert(anInt);
}
if (tree == null) {
return;
}
System.out.println("前序遍历这个树:");
binarySearchTree.prePrintTree(tree);
System.out.println("中序遍历这个树:");
binarySearchTree.inPrintTree(tree);
System.out.println("后续遍历这个树:");
binarySearchTree.postPrintTree(tree);
System.out.println("反转这颗树↓");
binarySearchTree.reverseTree(tree);
System.out.println("前序遍历这个树:");
binarySearchTree.prePrintTree(tree);
System.out.println("中序遍历这个树:");
binarySearchTree.inPrintTree(tree);
System.out.println("后续遍历这个树:");
binarySearchTree.postPrintTree(tree);
int target = 6;
TreeNode result = binarySearchTree.find(target);
if (result != null) {
System.out.println("找到了!这个树中包含有" + target + "元素");
} else {
System.out.println("没找到!这个树中不包含" + target + "元素");
}
int deleteTarget = 5;
System.out.println("删除值为" + deleteTarget + "的元素");
binarySearchTree.delete(deleteTarget);
System.out.println();
System.out.println("删除完后再遍历一波看看结果");
System.out.println("前序遍历这个树:");
binarySearchTree.prePrintTree(tree);
System.out.println("中序遍历这个树:");
binarySearchTree.inPrintTree(tree);
System.out.println("后续遍历这个树:");
binarySearchTree.postPrintTree(tree);
System.out.println("逆序遍历这个树:");
binarySearchTree.reversePrintTree(tree);
}
}