1 import java.util.LinkedList;
2 import java.util.Queue;
3 import java.util.Stack;
4
5 /**
6 * @author 阿遠
7 * Date: 2019/4/30
8 * Time: 15:23
9 */
10 public class BinarySearchTree<E extends Comparable<E>> {
11
12 // 内部类定义节点
13 private class Node{
14 public E e; // 节点值
15 public Node left, right; // 左右节点
16 // 构造函数
17 public Node(E e) {
18 this.e = e;
19 this.left = null;
20 this.right = null;
21 }
22 }
23
24 private Node root; // 根节点
25 private int size; // 深度
26
27 public BinarySearchTree() {
28 root = null;
29 size = 0;
30 }
31
32 public int size() {
33 return size;
34 }
35
36 public boolean isEmpty() {
37 return size == 0;
38 }
39
40 // 向二分搜索树中添加新的元素e
41 // public void add(E e) {
42 // if (root == null) {
43 // root = new Node(e);
44 // size ++;
45 // } else {
46 // add(root, e);
47 // }
48 // }
49 // 代码优化
50 public void add(E e) {
51 root = add(root, e);
52 }
53 // 向跟为node的二分搜索树种插入元素E,递归算法
54 // private void add(Node node, E e) {
55 // // 插入结束的条件
56 // if (e.equals(node.e)) { // 插入值与节点值相等
57 // return;
58 // } else if (e.compareTo(node.e) < 0 && node.left == null) { // 插入值小于节点并且左子树为空
59 // node.left = new Node(e);
60 // size ++;
61 // return;
62 // } else if (e.compareTo(node.e) > 0 && node.right == null) { // 插入值大于节点并且右子树为空
63 // node.right = new Node(e);
64 // size ++;
65 // return;
66 // }
67 // // 递归插入
68 // if(e.compareTo(node.e) < 0) {
69 // add(node.left , e);
70 // } else {
71 // add(node.right, e);
72 // }
73 // }
74 // add(Node node, E e) 代码优化: 返回插入新节点后的二分搜索树的根
75 private Node add(Node node, E e) {
76 if (node == null) {
77 size ++;
78 return new Node(e);
79 }
80 if (e.compareTo(node.e) < 0) {
81 node.left = add(node.left, e);
82 } else if (e.compareTo(node.e) > 0) {
83 node.right = add(node.right, e);
84 }
85 return node;
86 }
87
88 // 看二分搜索树中是否包含元素e
89 public boolean contains(E e) {
90 return contains(root, e);
91 }
92 private boolean contains(Node node, E e) {
93 if (node == null) {
94 return false;
95 }
96 // 结束条件
97 if (e.compareTo(node.e) == 0) {
98 return true;
99 }else if (e.compareTo(node.e) < 0) { // 没有结束就递归
100 return contains(node.left, e);
101 }else { //e.compareTo(node.e) > 0
102 return contains(node.right, e);
103 }
104 }
105
106 // 寻找二分搜索树的最小值
107 public E minimum() {
108 if (size == 0)
109 throw new IllegalArgumentException("BinarySearchTree is Empty");
110 return minimum(root).e;
111 }
112 private Node minimum(Node node) {
113 if (node.left == null)
114 return node;
115 return minimum(node.left);
116 }
117
118 // 寻找二分搜索树的最大值
119 public E maxmum() {
120 if (size == 0)
121 throw new IllegalArgumentException("BinarySearchTree is Empty");
122 return maxmum(root).e;
123 }
124 private Node maxmum(Node node) {
125 if (node.right == null)
126 return node;
127 return maxmum(node.right);
128 }
129
130 // 从二分搜索树中删除最小值所在节点,返回最小值
131 public E removeMin() {
132 E ret = minimum();
133 removeMin(root);
134 return ret;
135 }
136 // 删除掉以node为根的二分搜索树中的最小节点
137 // 返回删除节点后新的二分搜索树的根
138 private Node removeMin(Node node) {
139 if (node.left == null) {
140 Node rightNode = node.right;
141 node.right = null;
142 size --;
143 return rightNode;
144 }
145 node.left = removeMin(node.left);
146 return node;
147 }
148
149 // 从二分搜索树中删除最大值所在节点,返回最大值
150 public E removeMax() {
151 E ret = maxmum();
152 removeMax(root);
153 return ret;
154 }
155 // 删除掉以node为根的二分搜索树中的最小节点
156 // 返回删除节点后新的二分搜索树的根
157 private Node removeMax(Node node) {
158 if (node.right == null) {
159 Node leftNode = node.left;
160 node.left = null;
161 size --;
162 return leftNode;
163 }
164 node.right = removeMax(node.right);
165 return node;
166 }
167
168 // 从二分搜索树中删除元素为e节点
169 public void remove(E e) {
170 remove(root, e);
171 }
172 private Node remove(Node node, E e) {
173 if (node == null) // 如果二分搜索树为空
174 return null;
175 if (e.compareTo(node.e) < 0) {
176 node.left = remove(node.left,e);
177 return node;
178 } else if (e.compareTo(node.e) > 0) {
179 node.right = remove(node.right, e);
180 return node;
181 }else { // e == node.e
182 // 待删除左子树为空的情况
183 if (node.left == null) {
184 Node rightNode = node.left;
185 node.right = null;
186 size --;
187 return rightNode;
188 }
189 // 待删除右子树为空的情况
190 if (node.right == null) {
191 Node leftNode = node.left;
192 node.left = null;
193 size --;
194 return leftNode;
195 }
196 // 待删除节点左右子树均不为空的情况
197 // 找到比待删除节点大的最小节点,即将删除节点右子树的最小节点
198 // 用这个节点顶替待删除节点的位置
199 // 该方法的核心代码
200 Node successor = minimum(node.right); // 后继
201 successor.right = removeMax(node.right); // removeMax的作用是将node.right右子树的最小值删除
202 successor.left = node.left;
203 node.left = node.right = null;
204 return successor;
205 }
206 }
207
208 // 二分搜索树递归前序遍历
209 public void preOrder() {
210 preOrder(root);
211 }
212 private void preOrder(Node node) {
213 // 递归终止条件
214 if (node == null) {
215 return;
216 }
217 // 对递归元素进行操作
218 System.out.println(node.e);
219 // 没有结束就递归
220 preOrder(node.left);
221 preOrder(node.right);
222 }
223
224 // 二叉搜索树的非递归前序遍历
225 public void preOrderNR() {
226
227 Stack<Node> stack = new Stack<>();
228 stack.push(root);
229 while (!stack.isEmpty()) {
230 Node cur = stack.pop();
231 System.out.println(cur.e);
232 if (cur.right != null) {
233 stack.push(cur.right);
234 }
235 if (cur.left != null) {
236 stack.push(cur.left);
237 }
238 }
239 }
240
241 // 二分搜索树的中序遍历
242 public void inOrder() {
243 inOrder(root);
244 }
245 // 中序遍历以node为根的二分搜索树,递归算法 二分搜索树的中序遍历就是元素从小到大排序后的结果
246 private void inOrder(Node node) {
247 if (node == null) {
248 return;
249 }
250 inOrder(node.left);
251 System.out.println(node.e);
252 inOrder(node.right);
253 }
254
255 // 二分搜索树的后序遍历
256 public void postOrder() {
257 postOrder(root);
258 }
259 // 后序遍历以node为根的二分搜索树,递归算法
260 private void postOrder(Node node) {
261 if (node == null) {
262 return;
263 }
264 postOrder(node.left);
265 postOrder(node.right);
266 System.out.println(node.e);
267 }
268
269 // 前面实现的前中后三种遍历本质上都是深度优先的遍历,下面介绍层序遍历,以层为优先的遍历
270 // 层序遍历:一层一层的遍历
271 public void levelOrder() {
272 Queue<Node> q = new LinkedList<>(); // Queue在java中是一个借口,需使用具体的类(LinkedList)进行实现
273 q.add(root);
274 while (!q.isEmpty()) {
275 Node cur = q.remove();
276 System.out.println(cur.e);
277
278 if (cur.left != null)
279 q.add(cur.left);
280 if (cur.right != null)
281 q.add(cur.right);
282 }
283 }
284
285 @Override
286 public String toString() {
287 StringBuilder res = new StringBuilder();
288 generateBSTString(root, 0, res);
289 return res.toString();
290 }
291 // 生成以node为根节点,深度为depth的描述二叉树的字符串
292 private void generateBSTString(Node node, int depth, StringBuilder res) {
293 if (node == null) {
294 res.append(generateDepthString(depth) + node.e + "null\n");
295 return;
296 }
297 res.append(generateDepthString(depth) + node.e + "null\n");
298 generateBSTString(node.left, depth + 1, res);
299 generateBSTString(node.right, depth + 1, res);
300 }
301
302 private String generateDepthString(int depth) {
303 StringBuilder res = new StringBuilder();
304 for (int i = 0; i < depth; i ++) {
305 res.append("--");
306 }
307 return res.toString();
308 }
309 }