《算法》第三章部分程序 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的主要内容,如果未能解决你的问题,请参考以下文章

《算法》第三章部分程序 part 5

《算法》第三章部分程序 part 6

《算法》BEYOND 部分程序 part 2

《算法》第五章部分程序 part 2

《算法》第六章部分程序 part 7

《算法》第五章部分程序 part 1