《算法》第三章部分程序 part 2
Posted cuancuancuanhao
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《算法》第三章部分程序 part 2相关的知识,希望对你有一定的参考价值。
? 书中第三章部分程序,加上自己补充的代码,平衡二叉搜索树
● 平衡二叉搜索树
1 package package01; 2 3 import java.util.NoSuchElementException; 4 5 import edu.princeton.cs.algs4.Queue; 6 import edu.princeton.cs.algs4.StdIn; 7 import edu.princeton.cs.algs4.StdOut; 8 9 public class BST<Key extends Comparable<Key>, Value> 10 { 11 private class Node // 二叉树节点 12 { 13 private Key key; 14 private Value val; 15 private Node left, right; 16 private int size; // 节点总数(包括根节点和子树) 17 18 public Node(Key key, Value val, int size) 19 { 20 this.key = key; 21 this.val = val; 22 this.size = size; 23 } 24 } 25 26 private Node root; // 二叉树根节点 27 28 public BST() {} 29 30 public boolean isEmpty() 31 { 32 return size() == 0; 33 } 34 35 public int size() 36 { 37 return size(root); 38 } 39 40 private int size(Node x) 41 { 42 if (x == null) 43 return 0; 44 else 45 return x.size; 46 } 47 48 public boolean contains(Key key) // 判断 key 是否在树中 49 { 50 if (key == null) 51 throw new IllegalArgumentException(" <contains> key == null. "); 52 return get(key) != null; 53 } 54 55 public Value get(Key key) // 查找 56 { 57 if (key == null) 58 throw new IllegalArgumentException(" <get> key == null. "); 59 return getKernel(root, key); 60 } 61 62 private Value getKernel(Node x, Key key) // 查找内核,递归地向下找 63 { 64 if (x == null) 65 return null; 66 int cmp = key.compareTo(x.key); 67 if (cmp < 0) 68 return getKernel(x.left, key); 69 if (cmp > 0) 70 return getKernel(x.right, key); 71 return x.val; 72 } 73 74 public void put(Key key, Value val) // 插入 75 { 76 if (key == null) 77 throw new IllegalArgumentException(" <put> key == null. "); 78 if (val == null) // 空值插入作删除处理 79 delete(key); 80 else 81 root = putKernel(root, key, val); 82 //assert check(); // 对树作修改时需要检查 83 } 84 85 private Node putKernel(Node x, Key key, Value val) // 插入内核,插到适当的位置上去 86 { 87 if (x == null) 88 return new Node(key, val, 1); 89 int cmp = key.compareTo(x.key); 90 if (cmp < 0) 91 x.left = putKernel(x.left, key, val); 92 else if (cmp > 0) 93 x.right = putKernel(x.right, key, val); 94 else 95 x.val = val; 96 x.size = 1 + size(x.left) + size(x.right); 97 return x; 98 } 99 100 public void deleteMin() // 删除最小节点(先根序首节点) 101 { 102 if (isEmpty()) 103 throw new NoSuchElementException(" <deleteMin> underflow. "); 104 root = deleteMinKernel(root); 105 //assert check(); 106 } 107 108 private Node deleteMinKernel(Node x) // 删除最小节点内核 109 { 110 if (x.left == null) // 左子树为空,返回右子树(相当于删除根节点) 111 return x.right; 112 x.left = deleteMinKernel(x.left); // 左子树不空,继续往下找 113 x.size = size(x.left) + size(x.right) + 1; // 重新计算输的大小 114 return x; 115 } 116 117 public void deleteMax() // 删除最大节点(先根序末节点) 118 { 119 if (isEmpty()) 120 throw new NoSuchElementException(" <deleteMax> underflow. "); 121 root = deleteMaxKernel(root); 122 //assert check(); 123 } 124 125 private Node deleteMaxKernel(Node x) 126 { 127 if (x.right == null) // 右子树为空,返回左子树(相当于删除根节点) 128 return x.left; 129 x.right = deleteMaxKernel(x.right); // 右子树不空,继续往下找 130 x.size = size(x.left) + size(x.right) + 1; // 重新计算输的大小 131 132 return x; 133 } 134 135 public void delete(Key key) // 删除指定 key 的节点 136 { 137 if (key == null) 138 throw new IllegalArgumentException(" <delete> key == null. "); 139 root = deleteKernel(root, key); 140 assert check(); 141 } 142 143 private Node deleteKernel(Node x, Key key) // 删除节点内核 144 { 145 if (x == null) 146 return null; 147 int cmp = key.compareTo(x.key); 148 if (cmp < 0) 149 x.left = deleteKernel(x.left, key); 150 else if (cmp > 0) 151 x.right = deleteKernel(x.right, key); 152 else // 找到了目标键 153 { 154 if (x.right == null) // 右子树为空就返回左子树,左子树为空就返回右子树 155 return x.left; 156 if (x.left == null) 157 return x.right; 158 Node t = x; // 左右子树都不空,设这里中根序遍历为 x -> a -> b 159 x = min(t.right); // 找到 t 在中根序的下一个节点 a,赋给 x(结束后 x 的左子树一定为空) 160 x.right = deleteMinKernel(t.right); // 删除节点 a,删除函数返回 a 的下一个节点 b,赋给 x 的右子树 161 x.left = t.left; // 原来的的左子树接到 x 的左子树 162 } 163 x.size = 1 + size(x.left) + size(x.right); 164 return x; 165 } 166 167 public Key min() // 返回最小键 168 { 169 if (isEmpty()) 170 throw new NoSuchElementException(" <delete> empty. "); 171 return minKernel(root).key; 172 } 173 174 private Node minKernel(Node x) // 最小节点内核,需要递归 175 { 176 if (x.left == null) 177 return x; 178 return minKernel(x.left); 179 } 180 181 public Key max() // 返回最大键 182 { 183 if (isEmpty()) 184 throw new NoSuchElementException(" <max> empty. "); 185 return maxKernel(root).key; 186 } 187 188 private Node maxKernel(Node x) // 最大节点内核,需要递归 189 { 190 if (x.right == null) 191 return x; 192 return maxKernel(x.right); 193 } 194 195 public Key floor(Key key) // 返回不大于 key 的最大元素的键,不存在 196 { 197 if (key == null) 198 throw new IllegalArgumentException(" <floor> key == null. "); 199 if (isEmpty()) 200 throw new NoSuchElementException(" <floor> empty. "); 201 Node x = floorKernel(root, key); 202 return (x == null) ? null : return x.key; 203 } 204 205 private Node floorKernel(Node x, Key key) // floor 内核,需要递归 206 { 207 if (x == null) 208 return null; 209 int cmp = key.compareTo(x.key); 210 if (cmp == 0) 211 return x; 212 if (cmp < 0) 213 return floorKernel(x.left, key); 214 Node t = floorKernel(x.right, key); // 目标键较大时需要递归搜索 215 return (t == null) ? x : t; // 在母栈中保存了当前最好的结果 x,没有实现尾递归 216 } 217 218 public Key floor2(Key key) // floor 的尾递归实现 219 { 220 return floor2Kernel(root, key, null); 221 } 222 223 private Key floor2Kernel(Node x, Key key, Key best) // 调用时带上当前已经找到的最佳值 224 { 225 if (x == null) 226 return best; 227 int cmp = key.compareTo(x.key); 228 if (cmp == 0) 229 return x.key; 230 if (cmp < 0) 231 return floor2Kernel(x.left, key, best); 232 return floor2Kernel(x.right, key, x.key); 233 } 234 235 public Key ceiling(Key key) // 返回不小于 key 的最大元素的键 236 { 237 if (key == null) 238 throw new IllegalArgumentException(" <ceiling> key == null. "); 239 if (isEmpty()) 240 throw new NoSuchElementException(" <ceiling> empty. "); 241 Node x = ceilingKernel(root, key); 242 return (x == null) ? null : x.key; 243 } 244 245 private Node ceilingKernel(Node x, Key key) // ceiling 内核,需要递归 246 { 247 if (x == null) 248 return null; 249 int cmp = key.compareTo(x.key); 250 if (cmp == 0) 251 return x; 252 if (cmp > 0) 253 return ceilingKernel(x.right, key); 254 Node t = ceilingKernel(x.left, key); 255 return (t == null) ? x : t; 256 } 257 258 public Key ceiling2(Key key) // ceiling 的尾递归实现 259 { 260 return ceiling2Kernel(root, key, null); 261 } 262 263 private Key ceiling2Kernel(Node x, Key key, Key best) 264 { 265 if (x == null) 266 return best; 267 int cmp = key.compareTo(x.key); 268 if (cmp == 0) 269 return x.key; 270 if (cmp < 0) 271 return ceiling2Kernel(x.left, key, best); 272 return ceiling2Kernel(x.right, key, x.key); 273 } 274 275 public Key select(int k) // 取出排第 k 的元素 276 { 277 if (k < 0 || k >= size()) 278 throw new IllegalArgumentException(" <select> k < 0 || k >= size(). "); 279 return selectKernel(root, k).key; 280 } 281 282 private Node selectKernel(Node x, int k) // 取元素内核,需要递归 283 { 284 if (x == null) 285 return null; 286 int t = size(x.left); // 树的元素数用于来计数 287 if (k < t) 288 return selectKernel(x.left, k); 289 if (k > t) 290 return selectKernel(x.right, k - t - 1); 291 return x; 292 } 293 294 public int rank(Key key) // 计算键比 key 小的元素个数 295 { 296 if (key == null) 297 throw new IllegalArgumentException(" <rank> key == null. "); 298 return rankKernel(key, root); 299 } 300 301 private int rankKernel(Key key, Node x) // 计算函数内核,需要递归 302 { 303 if (x == null) 304 return 0; 305 int cmp = key.compareTo(x.key); 306 if (cmp < 0) 307 return rankKernel(key, x.left); 308 if (cmp > 0) 309 return 1 + size(x.left) + rankKernel(key, x.right); 310 return size(x.left); 311 } 312 313 public Iterable<Key> keys() // 创建队列用于迭代器,中根序 314 { 315 if (isEmpty()) 316 return new Queue<Key>(); 317 Key lo = min(), hi = max(); 318 if (lo == null) 319 throw new IllegalArgumentException(" <iterable> lo == null. "); 320 if (hi == null) 321 throw new IllegalArgumentException(" <iterable> hi == null. "); 322 Queue<Key> queue = new Queue<Key>(); 323 keysKernel(root, queue, lo, hi); 324 return queue; 325 } 326 327 private void keysKernel(Node x, Queue<Key> queue, Key lo, Key hi) // 创建迭代器内核,需要递归 328 { 329 if (x == null) 330 return; 331 int cmplo = lo.compareTo(x.key); 332 int cmphi = hi.compareTo(x.key); 333 if (cmplo < 0) 334 keysKernel(x.left, queue, lo, hi); 335 if (cmplo <= 0 && cmphi >= 0) 336 queue.enqueue(x.key); 337 if (cmphi > 0) 338 keysKernel(x.right, queue, lo, hi); 339 } 340 341 public int size(Key lo, Key hi) // 计算键落在给定范围内的元素个数 342 { 343 if (lo == null) 344 throw new IllegalArgumentException("first argument to size() is null"); 345 if (hi == null) 346 throw new IllegalArgumentException("second argument to size() is null"); 347 if (lo.compareTo(hi) > 0) 348 return 0; 349 if (contains(hi)) 350 return rank(hi) - rank(lo) + 1; 351 else 352 return rank(hi) - rank(lo); 353 } 354 355 public int height() // 计算树的高度 356 { 357 return heightKernel(root); 358 } 359 360 private int heightKernel(Node x) // 计算树高度内核,需要递归,空树高度为 -1,根节点高度为 0 361 { 362 if (x == null) 363 return -1; 364 return 1 + Math.max(heightKernel(x.left), heightKernel(x.right)); 365 } 366 367 public Iterable<Key> levelOrder() // 生成先根序队列 368 { 369 Queue<Key> keys = new Queue<Key>(); 370 Queue<Node> queue = new Queue<Node>(); 371 for (queue.enqueue(root); !queue.isEmpty();) 372 { 373 Node x = queue.dequeue(); 374 if (x == null) 375 continue; 376 keys.enqueue(x.key); 377 queue.enqueue(x.left); 378 queue.enqueue(x.right); 379 } 380 return keys; 381 } 382 383 private boolean check() // 检查函数,用于 debug 384 { 385 if (!isBST()) 386 StdOut.println(" <check> Not in symmetric order. "); 387 if (!isSizeConsistent()) 388 StdOut.println(" <check> Subtree counts not consistent. "); 389 if (!isRankConsistent()) 390 StdOut.println(" <check> Ranks not consistent. "); 391 return isBST() && isSizeConsistent() && isRankConsistent(); 392 } 393 394 private boolean isBST() // 检查输的保序性 395 { 396 return isBSTKernel(root, null, null); 397 } 398 399 private boolean isBSTKernel(Node x, Key min, Key max) 400 { 401 if (x == null) 402 return true; 403 if (min != null && x.key.compareTo(min) <= 0) 404 return false; 405 if (max != null && x.key.compareTo(max) >= 0) 406 return false; 407 return isBSTKernel(x.left, min, x.key) && isBSTKernel(x.right, x.key, max); 408 } 409 410 private boolean isSizeConsistent() // 检查树的 size 是否正确 411 { 412 return isSizeConsistentKernel(root); 413 } 414 415 private boolean isSizeConsistentKernel(Node x) 416 { 417 if (x == null) 418 return true; 419 if (x.size != size(x.left) + size(x.right) + 1) 420 return false; 421 return isSizeConsistentKernel(x.left) && isSizeConsistentKernel(x.right); 422 } 423 424 private boolean isRankConsistent() // 检查 rank 和 select 425 426 { 427 for (int i = 0; i < size(); i++) // 检查 rank 是否正确 428 { 429 if (i != rank(select(i))) 430 return false; 431 } 432 for (Key key : keys()) // 检查 select 是否正确 433 { 434 if (key.compareTo(select(rank(key))) != 0) 435 return false; 436 } 437 return true; 438 } 439 440 public static void main(String[] args) 441 { 442 BST<String, Integer> st = new BST<String, Integer>(); 443 for (int i = 0; !StdIn.isEmpty(); i++) // 放进树中 444 { 445 String key = StdIn.readString(); 446 st.put(key, i); 447 } 448 449 for (String s : st.levelOrder()) // 迭代器先根序遍历树 450 StdOut.println(s + " " + st.get(s)); 451 452 StdOut.println(); 453 for (String s : st.keys()) // 按键遍历树 454 StdOut.println(s + " " + st.get(s)); 455 } 456 }
以上是关于《算法》第三章部分程序 part 2的主要内容,如果未能解决你的问题,请参考以下文章