05 二分搜索樹(BinarySearchTree)
阿新 • • 發佈:2019-05-01
col while bst ole new rabl ebs bin lin
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 privateint 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 // 向二分搜索樹中添加新的元素e41 // 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 }
05 二分搜索樹(BinarySearchTree)