Algorithmen & Datenstrukturen mit Java: Beispielklasse für Verzeichnisse als Rot-Schwarz-Bä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/** This is a translation of a Haskell implementation
4 for red-black trees from
5 http://matt.might.net/articles/red-black-delete/
6 The Haskell source can be found under
7 http://matt.might.net/articles/red-black-delete/code/RedBlackSet.hs
8
9 This Java implementation is a PERSISTENT one and
10 it supports deletion.
11*/
12
13import ds.interfaces.Map;
14
15import ds.util.K; // example class for keys
16import ds.util.V; // example class for values
17import ds.util.KV; // key value pair
18import ds.util.Queue; // used by iterators
19import ds.util.Function2;
20import ds.util.NullIterator;
21
22import static ds.util.KV.mkPair;
23import static ds.util.Boolean.toInt;
24import static ds.util.Integer.max;
25import static ds.util.Integer.min;
26import static ds.util.Undef.undefined;
27
28import java.util.Iterator;
29
30import static java.lang.Integer.signum;
31
32//----------------------------------------
33
34public abstract
35 class RedBlackTree
36 implements Map {
37
38 /* trc *
39 static void msg(String s) {
40 System.out.println(s);
41 }
42
43 static RedBlackTree trc(String s, RedBlackTree t) {
44 msg(s + " " + t);
45 return t;
46 }
47 /**/
48
49 //----------------------------------------
50 // the smart constructors
51
52 // empty tree
53 public static
54 RedBlackTree empty() {
55 return
56 EMPTY;
57 }
58
59 // singleton tree
60 public static
61 RedBlackTree singleton(K k, V v) {
62 return
63 empty().insert(k, v);
64 }
65
66 // build search tree from arbitrary sequence (iterator)
67 public static
68 RedBlackTree fromIterator(Iterator<KV> elems) {
69
70 RedBlackTree res = empty();
71 while ( elems.hasNext() ) {
72 KV p = elems.next();
73 res = res.insert(p.fst, p.snd);
74 }
75 return
76 res;
77 }
78
79 public RedBlackTree
80 union(Map m2) {
81 return
82 unionWith(const2, m2);
83 }
84
85 // general unionWith by iterating over m2
86 public RedBlackTree
87 unionWith(Function2<V,V,V> op,
88 Map m2) {
89 Iterator<KV> i = m2.iterator();
90 RedBlackTree res = this;
91
92 while ( i.hasNext() ) {
93 KV kv2 = i.next();
94 K k2 = kv2.fst;
95 V v2 = kv2.snd;
96 V v1 = res.lookup(k2);
97 V vr = v1 == null ? v2 : op.apply(v1, v2);
98 res = res.insert(k2, vr);
99 }
100 return
101 res;
102 }
103
104 public RedBlackTree
105 difference(Map m2) {
106 return
107 differenceWith(null2, m2);
108 }
109
110 // general differenceWith by iterating over m2
111 public RedBlackTree
112 differenceWith(Function2<V,V,V> op,
113 Map m2) {
114
115 Iterator<KV> i = m2.iterator();
116 RedBlackTree res = this;
117
118 while ( i.hasNext() ) {
119 KV kv2 = i.next();
120 K k2 = kv2.fst;
121 V v2 = kv2.snd;
122 V v1 = res.lookup(k2);
123
124 if ( v1 != null ) { // key found in res
125 V vr = op.apply(v1, v2);
126 if ( vr == null )
127 res = res.remove(k2);
128 else
129 res = res.insert(k2, vr);
130 }
131 }
132 return
133 res;
134 }
135
136 public RedBlackTree copy() {
137 return
138 this;
139 }
140
141 //----------------------------------------
142 // special binary tree methods
143
144 abstract public int depth();
145 abstract public int minDepth();
146
147 public boolean member(K k) {
148 return
149 lookup(k) != null;
150 }
151
152 //----------------------------------------
153 // internal methods
154
155 // getter
156 Node node() { return nodeExpected(); }
157 int color() { return nodeExpected(); }
158 K key() { return nodeExpected(); }
159 V value() { return nodeExpected(); }
160 RedBlackTree left() { return nodeExpected(); }
161 RedBlackTree right() { return nodeExpected(); }
162
163 // tree manipulation
164 public RedBlackTree insert(K k, V v) {
165 assert k != null;
166
167 return
168 insert1(k, v).paintItBlack();
169 }
170
171 public RedBlackTree remove(K k) {
172 assert k != null;
173
174 return
175 remove1(k).paintItBlack();
176 }
177
178 // 2. iterator for descending enumeration
179
180 abstract public Iterator<KV> iteratorDesc();
181
182 public String toString() {
183 return
184 iterator().toString();
185 }
186
187 public boolean inv() {
188 return
189 invOrdered()
190 &&
191 invRedWithBlackChildren()
192 &&
193 noOfBlackNodes() != -1
194 &&
195 isBlack();
196 }
197
198
199 //----------------------------------------
200 // internal methods
201
202 abstract RedBlackTree insert1(K k, V v);
203 abstract RedBlackTree remove1(K k);
204
205 abstract boolean invRedWithBlackChildren();
206 abstract int noOfBlackNodes();
207 abstract boolean invOrdered();
208 abstract boolean allLS(K k);
209 abstract boolean allGT(K k);
210
211 // helper for ***With functions
212 private static <A> A nodeExpected() {
213 return
214 undefined("Node expected");
215 }
216
217 private static Function2<V,V,V> const2
218 = new Function2<V,V,V>() {
219 public V apply(V x, V y) {
220 return y;
221 }
222 };
223
224 private static Function2<V,V,V> null2
225 = new Function2<V,V,V>() {
226 public V apply(V x, V y) {
227 return null;
228 }
229 };
230
231 //----------------------------------------
232 // coloring
233
234 static final int NEGATIVE_BLACK = -1;
235 static final int RED = 0;
236 static final int BLACK = 1;
237 static final int DOUBLE_BLACK = 2;
238
239 static int blacker(int c) {
240 assert c < DOUBLE_BLACK;
241 return
242 c + 1;
243 }
244
245 static int redder(int c) {
246 assert c > NEGATIVE_BLACK;
247 return
248 c - 1;
249 }
250
251 boolean isRed() { return color() == RED; }
252 boolean isBlack() { return color() == BLACK; }
253 boolean isDoubleBlack() { return color() == DOUBLE_BLACK; }
254 boolean isNegativeBlack() { return color() == NEGATIVE_BLACK; }
255 boolean isEmptyDoubleBlack() { return false; }
256
257 abstract RedBlackTree paintItRed();
258 abstract RedBlackTree paintItBlack();
259
260 abstract RedBlackTree blacker();
261 abstract RedBlackTree redder();
262
263 //----------------------------------------
264 // the empty tree implemented by applying the singleton design pattern
265
266 // the "generic" empty list object (with a raw type)
267
268 private static final RedBlackTree EMPTY
269 = new Empty();
270
271 // the singleton class for the empty list object
272
273 private static
274 class Empty extends RedBlackTree {
275
276 public boolean isEmpty() {
277 return true;
278 }
279
280 public int size() {
281 return 0;
282 }
283
284 public int depth() {
285 return 0;
286 }
287
288 public int minDepth() {
289 return 0;
290 }
291
292 public V lookup(K k) {
293 return null;
294 }
295
296 public KV findMin() {
297 return nodeExpected();
298 }
299
300 public KV findMax() {
301 return nodeExpected();
302 }
303
304 public Iterator<KV> iterator() {
305 ++cntIter;
306 return
307 new NullIterator<KV>();
308 }
309 public Iterator<KV> iteratorDesc() {
310 return
311 iterator();
312 }
313
314 /* *
315 public String toString() {
316 return
317 ".";
318 }
319 /* */
320
321 //----------------------------------------
322 // not public stuff
323
324 Empty() { }
325
326 boolean invRedWithBlackChildren() { return true; }
327 int noOfBlackNodes() { return 1; }
328 boolean invOrdered() { return true; }
329 boolean allLS(K k) { return true; }
330 boolean allGT(K k) { return true; }
331
332 int color() {
333 return BLACK;
334 }
335
336 RedBlackTree insert1(K k, V v) {
337 return
338 new Node(k, v, RED, EMPTY, EMPTY);
339 }
340 RedBlackTree remove1(K k) {
341 return
342 this;
343 }
344 RedBlackTree paintItBlack() {
345 return
346 empty(); // works also for DoubleEmpty
347 }
348 RedBlackTree paintItRed() {
349 return
350 undefined("paintItRed on empty tree");
351 }
352 RedBlackTree blacker() {
353 return
354 doubleEmpty();
355 }
356 RedBlackTree redder() {
357 return
358 undefined("redder of empty tree");
359 }
360
361 }
362
363 //----------------------------------------
364 // double black empty tree
365 // helper for deletion
366
367 private static
368 RedBlackTree doubleEmpty() {
369 return
370 DOUBLE_EMPTY;
371 }
372
373 private static final RedBlackTree DOUBLE_EMPTY
374 = new DoubleEmpty();
375
376 // the singleton class for the double black empty tree
377
378 private static final
379 class DoubleEmpty extends Empty {
380
381 /* *
382 public String toString() {
383 return
384 "!";
385 }
386 /* */
387
388 DoubleEmpty() { }
389
390 int color() {
391 return DOUBLE_BLACK;
392 }
393
394 boolean isEmptyDoubleBlack() {
395 return true;
396 }
397
398 RedBlackTree blacker() {
399 return
400 undefined("blacker of double black");
401 }
402 RedBlackTree redder() {
403 return
404 empty();
405 }
406 }
407
408 //----------------------------------------
409 // the node class for none empty trees
410
411 private static final
412 class Node extends RedBlackTree {
413
414 /* persistent */
415 final K k;
416 final V v;
417 final int c; // the color
418 final RedBlackTree l;
419 final RedBlackTree r;
420
421 /* destructive *
422 K k;
423 V v;
424 int c;
425 RedBlackTree l;
426 RedBlackTree r;
427 /**/
428
429 Node(K k, V v, int c, RedBlackTree l, RedBlackTree r) {
430 assert k != null;
431
432 this.k = k;
433 this.v = v;
434 this.c = c;
435 this.l = l;
436 this.r = r;
437 ++cntNode;
438 }
439
440 /* destructive *
441 public RedBlackTree copy() {
442 return
443 new Node(k, v, c, l, r);
444 }
445 /**/
446
447 /* trc *
448 String toString() {
449 return
450 "(" + l + " " + k + "," + v + "," + c2s(c) + " " + r + ")";
451 }
452 /**/
453
454 private static String c2s(int c) {
455 switch ( c ) {
456 case NEGATIVE_BLACK: return "N";
457 case RED: return "R";
458 case BLACK: return "B";
459 case DOUBLE_BLACK: return "D";
460 }
461 return "";
462 }
463
464 //----------------------------------------
465 // predicates and attributes
466
467 public boolean isEmpty() {
468 return false;
469 }
470
471 public int size() {
472 return
473 1 + l.size() + r.size();
474 }
475
476 public int depth() {
477 return
478 1 + max(l.depth(), r.depth());
479 }
480
481 public int minDepth() {
482 return
483 1 + min(l.minDepth(), r.minDepth());
484 }
485
486 public V lookup(K k) {
487 assert k != null;
488
489 switch (signum(k.compareTo(this.k))) {
490 case -1:
491 return
492 l.lookup(k);
493 case 0:
494 return
495 v;
496 case +1:
497 return
498 r.lookup(k);
499 }
500 // never executed, but required
501 return
502 null;
503 }
504
505 //----------------------------------------
506 // getter
507
508 Node node() { return this; }
509 int color() { return c; }
510 K key() { return k; }
511 V value() { return v; }
512 RedBlackTree left() { return l; }
513 RedBlackTree right() { return r; }
514
515 public KV findMin() {
516 if ( l.isEmpty() )
517 return
518 mkPair(k, v);
519 return
520 l.findMin();
521 }
522
523 public KV findMax() {
524 if ( r.isEmpty() )
525 return
526 mkPair(k, v);
527 return
528 r.findMax();
529 }
530
531 public Iterator<KV> iterator() {
532 ++cntIter;
533 return
534 new NodeIterator(this);
535 }
536
537 public Iterator<KV> iteratorDesc() {
538 ++cntIter;
539 return
540 new NodeIteratorDescending(this);
541 }
542
543 //----------------------------------------
544 // invariant helpers
545
546 boolean invRedWithBlackChildren() {
547 return
548 ( ! isRed()
549 ||
550 ( l.isBlack() && r.isBlack() ) )
551 &&
552 l.invRedWithBlackChildren()
553 &&
554 r.invRedWithBlackChildren();
555 }
556
557 // -1 indicates # of black nodes differ
558 int noOfBlackNodes() {
559 int nl = l.noOfBlackNodes();
560 int nr = r.noOfBlackNodes();
561 return
562 (nl == nr && nl != -1)
563 ? nl + toInt(isBlack())
564 : -1;
565 }
566
567 boolean invOrdered() {
568 return
569 l.allLS(k)
570 &&
571 r.allGT(k)
572 &&
573 l.invOrdered()
574 &&
575 r.invOrdered();
576 }
577
578 boolean allLS(K k) {
579 return
580 this.k.compareTo(k) < 0
581 &&
582 r.allLS(k)
583 // && // redundant if only
584 // l.allLS(k) // used by inv
585 ;
586 }
587 boolean allGT(K k) {
588 return
589 this.k.compareTo(k) > 0
590 &&
591 l.allGT(k)
592 // && // redundant if only
593 // r.allGT(k) // used by inv
594 ;
595 }
596
597
598 //----------------------------------------
599 // getter
600
601 //----------------------------------------
602 // recoloring
603
604 RedBlackTree paintItBlack() {
605 return
606 setColor(BLACK);
607 }
608 RedBlackTree paintItRed() {
609 return
610 setColor(RED);
611 }
612 RedBlackTree blacker() {
613 return
614 setColor(blacker(color()));
615 }
616 RedBlackTree redder() {
617 return
618 setColor(redder(color()));
619 }
620
621 //----------------------------------------
622 // balancing
623
624 Node balance(int c, RedBlackTree t1, K k, V v, RedBlackTree t2) {
625 if ( c == BLACK )
626 return
627 balanceBlack(t1, k, v, t2);
628
629 // DOUBLE_BLACK only used in remove1
630 if ( c == DOUBLE_BLACK )
631 return
632 balanceDoubleBlack(t1, k, v, t2);
633
634 // no balancing at red nodes
635 return
636 set(k, v, c, t1, t2);
637 }
638
639 // Okasaki's rules for insertion balancing
640
641 Node balanceBlack(RedBlackTree l, K k, V v, RedBlackTree r) {
642 // pattern matching with java is pain in the ass
643
644 if ( l.isRed() ) {
645 Node ln = l.node();
646 if ( ln.l.isRed() ) {
647 Node lln = ln.l.node();
648 return
649 build3(RED, lln.l, lln.k, lln.v,
650 lln.r, ln.k, ln.v,
651 ln.r, k, v, r, ln, lln);
652 }
653 if ( ln.r.isRed() ) {
654 Node lrn = ln.r.node();
655 return
656 build3(RED, ln.l, ln.k, ln.v,
657 lrn.l, lrn.k, lrn.v,
658 lrn.r, k, v, r, ln, lrn);
659 }
660 }
661 if ( r.isRed() ) {
662 Node rn = r.node();
663 if ( rn.l.isRed() ) {
664 Node rln = rn.l.node();
665 return
666 build3(RED,
667 l, k, v,
668 rln.l, rln.k, rln.v,
669 rln.r, rn.k, rn.v,
670 rn.r,
671 rln, rn);
672 }
673 if ( rn.r.isRed() ) {
674 Node rrn = rn.r.node();
675 return
676 build3(RED,
677 l, k, v,
678 rn.l, rn.k, rn.v,
679 rrn.l, rrn.k, rrn.v,
680 rrn.r,
681 rrn, rn);
682 }
683 }
684 return
685 set(k, v, BLACK, l, r);
686 }
687
688 Node balanceDoubleBlack(RedBlackTree l, K k, V v, RedBlackTree r) {
689 // same rules as in balanceBlack, double black is absorbed
690
691 if ( l.isRed() ) {
692 Node ln = l.node();
693 if ( ln.l.isRed() ) {
694 Node lln = ln.l.node();
695 return
696 build3(BLACK,
697 lln.l, lln.k, lln.v,
698 lln.r, ln.k, ln.v,
699 ln.r, k, v,
700 r,
701 ln, lln);
702 }
703 if ( ln.r.isRed() ) {
704 Node lrn = ln.r.node();
705 return
706 build3(BLACK,
707 ln.l, ln.k, ln.v,
708 lrn.l, lrn.k, lrn.v,
709 lrn.r, k, v,
710 r,
711 ln, lrn);
712 }
713 }
714 if ( r.isRed() ) {
715 Node rn = r.node();
716 if ( rn.l.isRed() ) {
717 Node rln = rn.l.node();
718 return
719 build3(BLACK,
720 l, k, v,
721 rln.l, rln.k, rln.v,
722 rln.r, rn.k, rn.v,
723 rn.r,
724 rln, rn);
725 }
726 if ( rn.r.isRed() ) {
727 Node rrn = rn.r.node();
728 return
729 build3(BLACK,
730 l, k, v,
731 rn.l, rn.k, rn.v,
732 rrn.l, rrn.k, rrn.v,
733 rrn.r,
734 rrn, rn);
735 }
736 }
737
738 // extra rules for negative black none empty trees
739 if ( r.isNegativeBlack() ) {
740 Node rn = r.node();
741 if ( rn.l.isBlack()
742 &&
743 rn.r.isBlack() ) {
744 Node rln = rn.l.node();
745 return
746 rln.set(rln.k, rln.v, BLACK,
747 set(k, v, BLACK, l, rln.l),
748 rn.balanceBlack(rln.r, rn.k, rn.v, rn.r.paintItRed()));
749 }
750 }
751 if ( l.isNegativeBlack() ) {
752 Node ln = l.node();
753 if ( ln.l.isBlack()
754 &&
755 ln.r.isBlack() ) {
756 Node lrn = ln.r.node();
757 return
758 lrn.set(lrn.k, lrn.v, BLACK,
759 ln.balanceBlack(ln.l.paintItRed(), ln.k, ln.v, lrn.l),
760 set(k, v, BLACK, l, lrn.r));
761 }
762 }
763 return
764 set(k, v, DOUBLE_BLACK, l, r);
765 }
766
767 Node bubble(int c, RedBlackTree l, K k, V v, RedBlackTree r) {
768 if ( l.isDoubleBlack()
769 ||
770 r.isDoubleBlack() ) {
771 return
772 balance(blacker(c), l.redder(), k, v, r.redder());
773 }
774 return
775 balance(c, l, k, v, r);
776 }
777
778 // build 3 nodes from a b c and d with labels x y z
779 // when a destrutive set is used
780 // the root is stored in this
781 // the left node is stored in l
782 // the right node in r
783
784 Node build3(int rootColor,
785 RedBlackTree a, K xk, V xv,
786 RedBlackTree b, K yk, V yv,
787 RedBlackTree c, K zk, V zv,
788 RedBlackTree d,
789 Node l, Node r) {
790 return
791 set(yk, yv, rootColor,
792 l.set(xk, xv, BLACK, a, b),
793 r.set(zk, zv, BLACK, c, d));
794 }
795
796 //----------------------------------------
797 // setter
798
799 private Node set(K k, V v, int c,
800 RedBlackTree l,
801 RedBlackTree r) {
802 /* persistent */
803 if ( k == this.k && v == this.v
804 &&
805 c == this.c
806 &&
807 l == this.l && r == this.r )
808 return
809 this;
810 return
811 new Node(k, v, c, l, r);
812
813 /* destructive *
814 this.k = k;
815 this.v = v;
816 this.c = c;
817 this.l = l;
818 this.r = r;
819 return
820 this;
821 /**/
822 }
823 private Node setV(V v) {
824 /* persistent */
825 return
826 ( v == this.v )
827 ? this
828 : new Node(this.k, v, this.c, this.l, this.r);
829
830 /* destructive *
831 this.v = v;
832 return
833 this;
834 /**/
835 }
836
837 private Node setColor(int c) {
838 /* persistent */
839 return
840 c == this.c
841 ? this
842 : new Node(this.k, this.v, c, this.l, this.r);
843
844 /* destructive *
845 this.c = c;
846 return
847 this;
848 /**/
849 }
850
851 //----------------------------------------
852 // tree manipulation
853
854 RedBlackTree insert1(K k, V v) {
855 switch ( signum(k.compareTo(this.k)) ) {
856 case -1:
857 return
858 balance(c, l.insert1(k, v), this.k, this.v, r);
859 case 0:
860 return
861 setV(v);
862 case +1:
863 return
864 balance(c, l, this.k, this.v, r.insert1(k, v));
865 }
866 // never executed, but required
867 return
868 null;
869 }
870
871 RedBlackTree remove1(K k) {
872 switch ( signum(k.compareTo(this.k)) ) {
873 case -1:
874 return
875 bubble(c, l.remove1(k), this.k, this.v, r);
876 case 0:
877 return
878 removeRoot();
879 //trc("removeRoot",removeRoot());
880 case +1:
881 return
882 bubble(c, l, this.k, this.v, r.remove1(k));
883 }
884 // never executed, but required
885 return
886 null;
887 }
888
889 RedBlackTree removeRoot() {
890 if ( isRed()
891 &&
892 l.isEmpty()
893 &&
894 r.isEmpty()
895 )
896 return
897 empty();
898 if ( isBlack() ) {
899 if ( l.isEmpty()
900 &&
901 r.isEmpty() )
902 return
903 doubleEmpty();
904 if ( l.isRed()
905 &&
906 r.isEmpty() )
907 return
908 l.blacker();
909 if ( r.isRed()
910 &&
911 l.isEmpty() )
912 return
913 r.blacker();
914 }
915 KV p = l.findMax();
916 return
917 bubble(c, l.node().removeMax(), p.fst, p.snd, r);
918 }
919
920 RedBlackTree removeMax() {
921 if ( r.isEmpty() )
922 return
923 removeRoot();
924 return
925 bubble(c, l, k, v, r.node().removeMax());
926 }
927
928 //----------------------------------------
929 // iterators
930
931 // ascending enumeration
932
933 private static
934 class NodeIterator
935 extends ds.util.Iterator<KV> {
936
937 Queue queue;
938
939 NodeIterator(Node n) {
940 queue = Queue.empty();
941 add(n);
942 ++cntIter;
943 }
944
945 void add(Node n) {
946 queue = queue.cons(n);
947 if ( ! n.l.isEmpty() )
948 add(n.l.node()); // downcast
949 }
950
951 void addSubNodes(Node n) {
952 if ( ! n.r.isEmpty() )
953 add(n.r.node());
954 }
955
956 public boolean hasNext() {
957 return
958 ! queue.isEmpty();
959 }
960
961 public KV next() {
962 if ( queue.isEmpty() )
963 return
964 undefined("empty tree");
965
966 Node n = (Node)queue.head();
967 queue = queue.tail();
968 addSubNodes(n);
969 return
970 mkPair(n.k, n.v);
971 }
972 }
973
974 // descending enumeration
975
976 private
977 class NodeIteratorDescending
978 extends NodeIterator {
979
980 NodeIteratorDescending(Node n) {
981 super(n);
982 }
983
984 void add(Node n) {
985 queue = queue.cons(n);
986 if ( ! n.r.isEmpty() )
987 add(n.r.node()); // downcast
988 }
989
990 void addSubNodes(Node n) {
991 if ( ! n.l.isEmpty() )
992 add(n.l.node());
993 }
994 }
995 }
996
997 //----------------------------------------
998 // profiling
999
1000 private static int cntNode = 0;
1001 private static int cntIter = 0;
1002
1003 public static String stats() {
1004 return
1005 "stats for ds.persistent.map.RedBlackTree:\n" +
1006 "# new Node() : " + cntNode + "\n" +
1007 "# new Iterator() : " + cntIter + "\n";
1008 }
1009
1010 public String objStats() {
1011 int s = size();
1012 int o = s;
1013 int f = 5 * s;
1014 int m = o + f;
1015
1016 return
1017 "mem stats for ds.persistent.map.RedBlackTree object:\n" +
1018 "# elements (size) : " + s + "\n" +
1019 "# objects : " + o + "\n" +
1020 "# fields : " + f + "\n" +
1021 "# mem words : " + m + "\n";
1022 }
1023}
|
Letzte Änderung: 05.11.2015 | © Prof. Dr. Uwe Schmidt |