Algorithmen & Datenstrukturen mit Java: Beispielklasse für Verzeichnisse als binäre Suchbäume |
1package ds.interfaces;
2
3/** Simple interface for maps
4 */
5
6import java.util.Iterator;
7
8import ds.util.Invariant;
9import ds.util.Function2;
10
11import ds.util.K; // example class for keys
12import ds.util.V; // example class for values
13import ds.util.KV; // key value pair
14
15public
16 interface Map
17 extends Iterable<KV>,
18 Invariant {
19
20 boolean isEmpty();
21 boolean member(K k);
22 V lookup(K k);
23 int size();
24 KV findMin();
25 KV findMax();
26 Map insert(K k, V v);
27 Map remove(K k);
28 Map union(Map m2);
29 Map difference(Map m2);
30 Map unionWith(Function2<V,V,V> op, Map m2);
31 Map differenceWith(Function2<V,V,V> op, Map m2);
32 Map copy();
33
34 // inherited
35
36 // public Iterator<KV> iterator();
37 // public inv();
38}
1package ds.persistent.map;
2
3/** Persistent implementation of binary search treee.
4 Operations manipulating trees always create copies
5 of the objects to be manipulated. This assures, that
6 old trees remains unchanged.
7
8 Binary search trees require a total ordering
9 on the key.
10*/
11
12import ds.interfaces.Map;
13
14import ds.util.K; // example class for keys
15import ds.util.V; // example class for values
16import ds.util.KV; // key value pair
17import ds.util.Queue; // for iterators
18import ds.util.Function2;
19import ds.util.NullIterator;
20
21import static ds.util.KV.mkPair;
22import static ds.util.Integer.max;
23import static ds.util.Integer.min;
24import static ds.util.Undef.undefined;
25
26import java.util.Iterator;
27
28import static java.lang.Integer.signum;
29
30//----------------------------------------
31
32public abstract
33 class BinaryTree
34 implements Map {
35
36 //----------------------------------------
37 // the smart constructors
38
39 // empty tree
40 public static
41 BinaryTree empty() {
42 return
43 EMPTY;
44 }
45
46 // singleton tree
47 public static
48 BinaryTree singleton(K k, V v) {
49 return
50 new Node(k, v, EMPTY, EMPTY);
51 }
52
53 // build search tree from arbitrary sequence (iterator)
54 public static
55 BinaryTree fromIterator(Iterator<KV> elems) {
56
57 BinaryTree res = empty();
58 while ( elems.hasNext() ) {
59 KV p = elems.next();
60 res = res.insert(p.fst, p.snd);
61 }
62 return
63 res;
64 }
65
66 // smart constructor for building a balanced search tree
67 // out of an ascending sorted sequence of values
68 // The length of the sequence must be known in advance
69
70 public static
71 BinaryTree rebuild(Iterator<KV> elems, int len) {
72
73 if ( len == 0 )
74 return EMPTY;
75
76 int lenL = len / 2;
77 int lenR = len - lenL - 1;
78
79 BinaryTree l = rebuild(elems, lenL);
80 KV p = elems.next();
81 BinaryTree r = rebuild(elems, lenR);
82
83 return
84 new Node(p.fst, p.snd, l, r);
85 }
86
87 //----------------------------------------
88 // public methods
89
90 public abstract BinaryTree insert(K k, V v);
91 public abstract BinaryTree remove(K k);
92
93 public boolean member(K k) {
94 return
95 lookup(k) != null;
96 }
97
98 public BinaryTree
99 union(Map m2) {
100 return
101 unionWith(const2, m2);
102 }
103
104 // general unionWith by iterating over m2
105 // this has poor runtime, Why? O(???)?
106
107 public BinaryTree
108 unionWith(Function2<V,V,V> op,
109 Map m2) {
110 Iterator<KV> i = m2.iterator();
111 BinaryTree res = this;
112
113 while ( i.hasNext() ) {
114 KV kv2 = i.next();
115 K k2 = kv2.fst;
116 V v2 = kv2.snd;
117 V v1 = res.lookup(k2);
118 V vr = v1 == null ? v2 : op.apply(v1, v2);
119 res = res.insert(k2, vr);
120 }
121 return
122 res;
123 }
124
125 public BinaryTree
126 difference(Map m2) {
127 return
128 differenceWith(null2, m2);
129 }
130
131 public BinaryTree
132 differenceWith(Function2<V,V,V> op,
133 Map m2) {
134 // general differenceWith by iterating over m2
135 // this has also poor runtime, Why? O(???)
136
137 Iterator<KV> i = m2.iterator();
138 BinaryTree res = this;
139
140 while ( i.hasNext() ) {
141 KV kv2 = i.next();
142 K k2 = kv2.fst;
143 V v2 = kv2.snd;
144 V v1 = res.lookup(k2);
145
146 if ( v1 != null ) { // key found in res
147 V vr = op.apply(v1, v2);
148 if ( vr == null )
149 res = res.remove(k2);
150 else
151 res = res.insert(k2, vr);
152 }
153 }
154 return
155 res;
156 }
157
158 public String toString() {
159 return
160 iterator().toString();
161 }
162
163 public BinaryTree copy() {
164 return
165 this;
166 }
167
168 //----------------------------------------
169 // special binary tree methods
170
171 abstract public int depth();
172 abstract public int minDepth();
173
174 public boolean balanced() {
175 return
176 depth() <= minDepth() + 1;
177 }
178
179 public BinaryTree balance() {
180 return
181 rebuild(iterator(), size());
182 }
183
184 // 2. iterator for descending enumeration
185 abstract public Iterator<KV> iteratorDesc();
186
187 abstract public Iterator<KV> iteratorBreadthFirst();
188
189 public KV findRoot() {
190 return nodeExpected();
191 }
192
193 //----------------------------------------
194 // internal methods
195
196 // getter
197 Node node() { return nodeExpected(); }
198 K key() { return nodeExpected(); }
199 V value() { return nodeExpected(); }
200 BinaryTree left() { return nodeExpected(); }
201 BinaryTree right() { return nodeExpected(); }
202
203 // helper for inv
204 abstract boolean allLS(K k);
205 abstract boolean allGT(K k);
206
207 // helper for union
208 // split a tree into letf and right part
209 // and optinally a root with key k and attr v
210 // here k and v of the result may be null
211 abstract Node splitAt(K k);
212
213 private static <A> A nodeExpected() {
214 return
215 undefined("Node expected");
216 }
217
218 // helper for ***With functions
219 private static Function2<V,V,V> const2
220 = new Function2<V,V,V>() {
221 public V apply(V x, V y) {
222 return y;
223 }
224 };
225
226 private static Function2<V,V,V> null2
227 = new Function2<V,V,V>() {
228 public V apply(V x, V y) {
229 return null;
230 }
231 };
232
233 //----------------------------------------
234 // the empty tree implemented by applying
235 // the singleton design pattern
236
237 // the "generic" empty tree object
238
239 private static final BinaryTree EMPTY
240 = new Empty();
241
242 // the singleton class for the empty tree object
243
244 private static final
245 class Empty
246 extends BinaryTree {
247
248 // predicates and attributes
249 public boolean isEmpty() {
250 return true;
251 }
252
253 public int size() {
254 return 0;
255 }
256
257 public int depth() {
258 return 0;
259 }
260
261 public int minDepth() {
262 return 0;
263 }
264
265 public V lookup(K k) {
266 return null;
267 }
268
269 public KV findMin() {
270 return nodeExpected();
271 }
272
273 public KV findMax() {
274 return nodeExpected();
275 }
276
277 public boolean inv() {
278 return true;
279 }
280
281 public Iterator<KV> iterator() {
282 ++cntIter;
283 return
284 new NullIterator<KV>();
285 }
286
287 public Iterator<KV> iteratorDesc() {
288 return
289 iterator();
290 }
291
292 public Iterator<KV> iteratorBreadthFirst() {
293 return
294 iterator();
295 }
296
297 // tree manipulation
298 public BinaryTree insert(K k, V v) {
299 return
300 singleton(k, v);
301 }
302
303 public BinaryTree remove(K k) {
304 return
305 this;
306 }
307
308 public BinaryTree
309 unionWith(Function2<V,V,V> op,
310 Map m2) {
311 return
312 (BinaryTree)m2;
313 }
314
315 public BinaryTree
316 differenceWith(Function2<V,V,V> op,
317 Map m2) {
318 return
319 this;
320 }
321
322 public BinaryTree balance() {
323 return
324 this;
325 }
326
327 //----------------------------------------
328 // not public stuff
329
330 Empty() { }
331
332 boolean allLS(K k) {
333 return true;
334 }
335 boolean allGT(K k) {
336 return true;
337 }
338
339 Node splitAt(K k) {
340 return
341 new Node(null, null, EMPTY, EMPTY);
342 }
343 }
344
345 //----------------------------------------
346 // the node class for none empty trees
347
348 private static final
349 class Node
350 extends BinaryTree {
351
352 /* persistent */
353 final K k;
354 final V v;
355 final BinaryTree l;
356 final BinaryTree r;
357
358 /* destructive *
359 K k;
360 V v;
361 BinaryTree l;
362 BinaryTree r;
363 /**/
364
365 Node(K k, V v, BinaryTree l, BinaryTree r) {
366 assert k != null;
367
368 this.k = k;
369 this.v = v;
370 this.l = l;
371 this.r = r;
372 ++cntNode;
373 }
374
375 //----------------------------------------
376 // predicates and attributes
377
378 public boolean isEmpty() {
379 return false;
380 }
381
382 public int size() {
383 return
384 1 + l.size() + r.size();
385 }
386
387 public int depth() {
388 return
389 1 + max(l.depth(), r.depth());
390 }
391
392 public int minDepth() {
393 return
394 1 + min(l.minDepth(), r.minDepth());
395 }
396
397 public V lookup(K k) {
398 assert k != null;
399
400 switch (signum(k.compareTo(this.k))) {
401 case -1:
402 return
403 l.lookup(k);
404 case 0:
405 return
406 v;
407 case +1:
408 return
409 r.lookup(k);
410 }
411 // never executed, but required by javac
412 return
413 null;
414 }
415
416 public boolean inv() {
417 return
418 l.allLS(k)
419 &&
420 r.allGT(k)
421 &&
422 l.inv()
423 &&
424 r.inv();
425 }
426
427 //----------------------------------------
428
429 public KV findRoot() {
430 return
431 mkPair(key(), value());
432 }
433
434
435 public KV findMin() {
436 if ( l.isEmpty() )
437 return
438 mkPair(k, v);
439 return
440 l.findMin();
441 }
442
443 public KV findMax() {
444 if ( r.isEmpty() )
445 return
446 mkPair(k, v);
447 return
448 r.findMax();
449 }
450
451 public Iterator<KV> iterator() {
452 return
453 new NodeIterator(this);
454 }
455
456 public Iterator<KV> iteratorDesc() {
457 return
458 new NodeIteratorDescending(this);
459 }
460
461 public Iterator<KV> iteratorBreadthFirst() {
462 return
463 new NodeIteratorBF(this);
464 }
465 //----------------------------------------
466 // internal methods
467
468 // getter
469 Node node() { return this; }
470 K key() { return k; }
471 V value() { return v; }
472 BinaryTree left() { return l; }
473 BinaryTree right() { return r; }
474
475
476 // helper for inv
477
478 boolean allLS(K k) {
479 return
480 this.k.compareTo(k) < 0
481 &&
482 r.allLS(k)
483 // && // redundant if only
484 // l.allLS(k) // used by inv
485 ;
486 }
487
488 boolean allGT(K k) {
489 return
490 this.k.compareTo(k) > 0
491 &&
492 l.allGT(k)
493 // && // redundant if only
494 // r.allGT(k) // used by inv
495 ;
496 }
497
498 // helper for union
499
500 Node splitAt(K k) {
501 switch ( signum(k.compareTo(this.k)) ) {
502 case -1:
503 Node rl = l.splitAt(k);
504 return
505 rl.setR(this.setL(rl.r));
506 case 0:
507 return
508 this;
509 case +1:
510 Node rr = r.splitAt(k);
511 return
512 rr.setL(this.setR(rr.l));
513 }
514 // dead code
515 return
516 null;
517 }
518
519
520 // setter
521
522 private Node set(K k, V v,
523 BinaryTree l,
524 BinaryTree r) {
525 /* persistent */
526 if ( k == this.k && v == this.v
527 &&
528 l == this.l && r == this.r
529 )
530 return
531 this;
532 return
533 new Node(k, v, l, r);
534
535 /* destructive *
536 this.k = k;
537 this.v = v;
538 this.l = l;
539 this.r = r;
540 return
541 this;
542 /**/
543 }
544 private Node setL(BinaryTree l) {
545 /* persistent */
546 if ( l == this.l )
547 return
548 this;
549 return
550 new Node(this.k, this.v, l, this.r);
551
552 /* destructive *
553 this.l = l;
554 return
555 this;
556 /**/
557 }
558 private Node setR(BinaryTree r) {
559 /* persistent */
560 if ( r == this.r )
561 return
562 this;
563 return
564 new Node(this.k, this.v, this.l, r);
565
566 /* destructive *
567 this.r = r;
568 return
569 this;
570 /**/
571 }
572 private Node setV(V v) {
573 /* persistent */
574 return
575 ( v == this.v )
576 ? this
577 : new Node(this.k, v, this.l, this.r);
578
579 /* destructive *
580 this.v = v;
581 return
582 this;
583 /**/
584 }
585
586 //----------------------------------------
587 // tree manipulation
588
589 public BinaryTree insert(K k, V v) {
590 assert k != null;
591
592 switch ( signum(k.compareTo(this.k)) ) {
593 case -1:
594 return
595 setL(l.insert(k,v));
596 case 0:
597 return
598 setV(v);
599 case +1:
600 return
601 setR(r.insert(k, v));
602 }
603 // never executed, but required by javac
604 return
605 null;
606 }
607
608 public BinaryTree remove(K k) {
609 assert k != null;
610
611 switch ( signum(k.compareTo(this.k)) ) {
612 case -1:
613 return
614 setL(l.remove(k));
615 case 0:
616 return
617 removeRoot();
618 case +1:
619 return
620 setR(r.remove(k));
621 }
622 // never executed, but required by javac
623 return
624 null;
625 }
626
627 private BinaryTree removeRoot() {
628 if ( l.isEmpty() )
629 return
630 r;
631 if ( r.isEmpty() )
632 return
633 l;
634
635 // take maximum value in left tree as new root
636 KV maxL = l.findMax();
637 BinaryTree newL = l.remove(maxL.fst);
638
639 return
640 set(maxL.fst, maxL.snd, newL, r);
641 }
642
643 // fast union
644 // merging of trees is done with respect to order in m2
645 public BinaryTree
646 unionWith(Function2<V,V,V> op,
647 Map m2) {
648 BinaryTree t2 = (BinaryTree)m2;
649 if ( t2.isEmpty() )
650 return
651 this;
652
653 Node splitm2 = t2.splitAt(k);
654 BinaryTree lr = l.unionWith(op, splitm2.l);
655 BinaryTree rr = r.unionWith(op, splitm2.r);
656 V vr = splitm2.k == null ? v : op.apply(v, splitm2.v);
657 return
658 set(k, vr, lr, rr);
659 }
660
661
662 /* destructive *
663 public BinaryTree copy() {
664 return
665 new Node(k, v,
666 l.copy(),
667 r.copy());
668 }
669 /**/
670
671 //----------------------------------------
672 // iterators
673
674 // ascending enumeration
675
676 private static
677 class NodeIterator
678 extends ds.util.Iterator<KV> {
679
680 Queue queue;
681
682 NodeIterator(Node n) {
683 queue = Queue.empty();
684 add(n);
685 ++cntIter;
686 }
687
688 void add(Node n) {
689 queue = queue.cons(n);
690 if ( ! n.l.isEmpty() ) {
691 add(n.l.node()); // downcast
692 }
693 }
694
695 void addSubNodes(Node n) {
696 if ( ! n.r.isEmpty() )
697 add(n.r.node());
698 }
699
700 public boolean hasNext() {
701 return
702 ! queue.isEmpty();
703 }
704
705 public KV next() {
706 if ( queue.isEmpty() )
707 return
708 undefined("empty tree");
709
710 Node n = (Node)queue.head();
711 queue = queue.tail();
712 addSubNodes(n);
713 return
714 mkPair(n.k, n.v);
715 }
716 } // end NodeIterator
717
718 // descending enumeration
719 private
720 class NodeIteratorDescending
721 extends NodeIterator {
722
723 NodeIteratorDescending(Node n) {
724 super(n);
725 }
726
727 void add(Node n) {
728 queue = queue.cons(n);
729 if ( ! n.r.isEmpty() )
730 add(n.r.node()); // downcast
731 }
732
733 void addSubNodes(Node n) {
734 if ( ! n.l.isEmpty() )
735 add(n.l.node());
736 }
737 } // end NodeIteratorDescending
738
739 // descending enumeration
740 private
741 class NodeIteratorBF
742 extends NodeIterator {
743
744 NodeIteratorBF(Node n) {
745 super(n);
746 }
747
748 void add(Node n) {
749 // add the nodes at the bottom
750 queue = queue.append(n);
751 }
752
753 void addSubNodes(Node n) {
754 if ( ! n.l.isEmpty() )
755 add(n.l.node());
756 if ( ! n.r.isEmpty() )
757 add(n.r.node());
758 }
759 } // end NodeIteratorBF
760 }
761
762 //----------------------------------------
763 // profiling
764
765 private static int cntNode = 0;
766 private static int cntIter = 0;
767
768 public static String stats() {
769 return
770 "stats for ds.persistent.map.BinaryTree:\n" +
771 "# new Node() : " + cntNode + "\n" +
772 "# new Iterator() : " + cntIter + "\n";
773 }
774
775 public String objStats() {
776 int s = size();
777 int o = s;
778 int f = 4 * s;
779 int m = o + f;
780
781 return
782 "mem stats for ds.persistent.map.BinaryTree object:\n" +
783 "# elements (size) : " + s + "\n" +
784 "# objects : " + o + "\n" +
785 "# fields : " + f + "\n" +
786 "# mem words : " + m + "\n";
787 }
788}
|
Letzte Änderung: 08.12.2015 | © Prof. Dr. Uwe Schmidt |