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 "); 295 return; 296 } 297 res.append(generateDepthString(depth) + node.e + "null "); 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 }