KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > prefuse > util > collections > AbstractTreeMap


1 package prefuse.util.collections;
2
3 import java.util.Comparator JavaDoc;
4 import java.util.ConcurrentModificationException JavaDoc;
5 import java.util.NoSuchElementException JavaDoc;
6
7
8 /**
9  * Abstract base class for red-black trees that map a key value to
10  * an int value.
11  *
12  * @author <a HREF="http://jheer.org">jeffrey heer</a>
13  */

14 public abstract class AbstractTreeMap implements IntSortedMap {
15
16     protected static final boolean RED = false;
17     protected static final boolean BLACK = true;
18     
19     protected static final Entry NIL = new Entry(Integer.MIN_VALUE);
20     static {
21         NIL.left = NIL.right = NIL.p = NIL;
22     }
23     
24     protected LiteralComparator cmp = null;
25     protected Entry root = NIL;
26     
27     protected boolean allowDuplicates;
28     protected int size = 0;
29     protected int unique = 0;
30     protected int modCount = 0;
31     protected int lastOrder = 0;
32     
33     // ------------------------------------------------------------------------
34
// Constructors
35

36     public AbstractTreeMap(LiteralComparator comparator,
37                                boolean allowDuplicates)
38     {
39         this.cmp = comparator==null ? DefaultLiteralComparator.getInstance()
40                                     : comparator;
41         this.allowDuplicates = allowDuplicates;
42     }
43
44     // ------------------------------------------------------------------------
45
// Accessor Methods
46

47     public boolean isAllowDuplicates() {
48         return allowDuplicates;
49     }
50     
51     /**
52      * @see java.util.Map#size()
53      */

54     public int size() {
55         return size;
56     }
57     
58     public boolean isEmpty() {
59         return root == NIL;
60     }
61     
62     /**
63      * @see java.util.SortedMap#comparator()
64      */

65     public Comparator JavaDoc comparator() {
66         return cmp;
67     }
68     
69     // ------------------------------------------------------------------------
70
// SortedMap Methods
71

72     /**
73      * @see java.util.Map#clear()
74      */

75     public void clear() {
76         ++modCount;
77         size = 0;
78         root = NIL;
79     }
80
81     public int getMinimum() {
82         return minimum(root).getValue();
83     }
84     
85     public int getMaximum() {
86         return maximum(root).getValue();
87     }
88     
89     public int getMedian() {
90         Entry e = minimum(root);
91         for ( int i=0; i<size/2; ++i, e=successor(e) );
92         return e.getValue();
93     }
94     
95     public int getUniqueCount() {
96         return unique;
97     }
98     
99     /**
100      * @see java.util.Map#containsValue(java.lang.Object)
101      */

102     public boolean containsValue(int value) {
103         return (root == NIL ? false : containsValue(root, value));
104     }
105     
106     private boolean containsValue(Entry e, int value) {
107         if ( e.val == value ) {
108             return true;
109         } else {
110             return (e.left != NIL && containsValue(e.left, value)) ||
111                    (e.right != NIL && containsValue(e.right, value));
112         }
113     }
114     
115     // -- Collection view methods ---------------------------------------------
116

117     public IntIterator valueIterator(boolean ascend) {
118         return new ValueIterator(new EntryIterator(!ascend));
119     }
120     
121     // ------------------------------------------------------------------------
122
// Internal update methods
123

124     protected void incrementSize(boolean isUnique) {
125         ++size; ++modCount;
126         if ( isUnique ) ++unique;
127     }
128     
129     protected void decrementSize(boolean isUnique) {
130         --size; ++modCount;
131         if ( isUnique ) --unique;
132     }
133     
134     // ------------------------------------------------------------------------
135
// Internal Binary Search Tree / Red-Black Tree methods
136
// Adapted from Cormen, Leiserson, and Rivest's Introduction to Algorithms
137

138     protected abstract int compare(Entry e1, Entry e2);
139     
140     protected Entry find(Entry x) {
141         Entry y = root;
142         while (y != NIL) {
143             int cmp = compare(x, y);
144             if (cmp == 0)
145                 return y;
146             else if (cmp < 0)
147                 y = y.left;
148             else
149                 y = y.right;
150         }
151         return y;
152     }
153     
154     protected Entry findPredecessor(Entry x) {
155         Entry y = root;
156         while (y != NIL) {
157             int cmp = compare(x, y);
158             if (cmp > 0) {
159                 if ( y.right == NIL )
160                     return y;
161                 y = y.right;
162             } else {
163                 if ( y.left != NIL ) {
164                     y = y.left;
165                 } else {
166                     Entry up = y.p, c = y;
167                     for ( ; up != NIL && c == up.left; c = up, up = up.p );
168                     return up;
169                 }
170             }
171         }
172         return y;
173     }
174     
175     protected Entry findCeiling(Entry x) {
176         Entry y = root;
177
178         while ( y != NIL ) {
179             int cmp = compare(x, y);
180             if (cmp == 0) {
181                 return y;
182             } else if (cmp < 0) {
183                 if (y.left != NIL)
184                     y = y.left;
185                 else
186                     return y;
187             } else {
188                 if (y.right != NIL) {
189                     y = y.right;
190                 } else {
191                     Entry up = y.p, c = y;
192                     for ( ; up != NIL && c == up.right; c = up, up = up.p );
193                     return up;
194                 }
195             }
196         }
197         return y;
198     }
199     
200     protected Entry minimum(Entry x) {
201         for ( ; x.left != NIL; x = x.left );
202         return x;
203     }
204     
205     protected Entry maximum(Entry x) {
206         for ( ; x.right != NIL; x = x.right );
207         return x;
208     }
209     
210     protected Entry successor(Entry x) {
211         // easy case - just traverse to the right
212
if ( x.right != NIL ) return minimum(x.right);
213         
214         // else have to climb up
215
Entry y = x.p;
216         while ( y != NIL && x == y.right ) {
217             x = y;
218             y = y.p;
219         }
220         return y;
221     }
222     
223     protected Entry predecessor(Entry x) {
224         // easy case - just traverse to the left
225
if ( x.left != NIL ) return maximum(x.left);
226         
227         // else have to climb up
228
Entry y = x.p;
229         while ( y != NIL && x == y.left ) {
230             x = y;
231             y = y.p;
232         }
233         return y;
234     }
235     
236     protected void rotateLeft(Entry x) {
237         Entry y = x.right;
238         x.right = y.left;
239         if (y.left != NIL)
240             y.left.p = x;
241         y.p = x.p;
242         if (x.p == NIL)
243             root = y;
244         else if (x.p.left == x)
245             x.p.left = y;
246         else
247             x.p.right = y;
248         y.left = x;
249         x.p = y;
250     }
251
252     protected void rotateRight(Entry x) {
253         Entry y = x.left;
254         x.left = y.right;
255         if (y.right != NIL)
256             y.right.p = x;
257         y.p = x.p;
258         if (x.p == NIL)
259             root = y;
260         else if (x.p.right == x)
261             x.p.right = y;
262         else x.p.left = y;
263         y.right = x;
264         x.p = y;
265     }
266
267     protected void fixUpInsert(Entry x) {
268         x.color = RED;
269
270         while (x != NIL && x != root && x.p.color == RED) {
271             if (x.p == x.p.p.left) {
272                 Entry y = x.p.p.right;
273                 if (y.color == RED) {
274                     x.p.color = BLACK;
275                     y.color = BLACK;
276                     x.p.p.color = RED;
277                     x = x.p.p;
278                 } else {
279                     if (x == x.p.right) {
280                         x = x.p;
281                         rotateLeft(x);
282                     }
283                     x.p.color = BLACK;
284                     x.p.p.color = RED;
285                     if (x.p.p != NIL)
286                         rotateRight(x.p.p);
287                 }
288             } else {
289                 // mirror image case
290
Entry y = x.p.p.left;
291                 if (y.color == RED) {
292                     x.p.color = BLACK;
293                     y.color = BLACK;
294                     x.p.p.color = RED;
295                     x = x.p.p;
296                 } else {
297                     if (x == x.p.left) {
298                         x = x.p;
299                         rotateRight(x);
300                     }
301                     x.p.color = BLACK;
302                     x.p.p.color = RED;
303                     if (x.p.p != NIL)
304                         rotateLeft(x.p.p);
305                 }
306             }
307         }
308         root.color = BLACK;
309     }
310     
311     protected void fixUpRemove(Entry x) {
312         while (x != root && x.color == BLACK) {
313             if (x == x.p.left) {
314                 Entry sib = x.p.right;
315
316                 if (sib.color == RED) {
317                     sib.color = BLACK;
318                     x.p.color = RED;
319                     rotateLeft(x.p);
320                     sib = x.p.right;
321                 }
322
323                 if (sib.left.color == BLACK &&
324                     sib.right.color == BLACK) {
325                     sib.color = RED;
326                     x = x.p;
327                 } else {
328                     if (sib.right.color == BLACK) {
329                         sib.left.color = BLACK;
330                         sib.color = RED;
331                         rotateRight(sib);
332                         sib = x.p.right;
333                     }
334                     sib.color = x.p.color;
335                     x.p.color = BLACK;
336                     sib.right.color = BLACK;
337                     rotateLeft(x.p);
338                     x = root;
339                 }
340             } else {
341                 // mirror image case
342
Entry sib = x.p.left;
343
344                 if (sib.color == RED) {
345                     sib.color = BLACK;
346                     x.p.color = RED;
347                     rotateRight(x.p);
348                     sib = x.p.left;
349                 }
350
351                 if (sib.right.color == BLACK &&
352                     sib.left.color == BLACK) {
353                     sib.color = RED;
354                     x = x.p;
355                 } else {
356                     if (sib.left.color == BLACK) {
357                         sib.right.color = BLACK;
358                         sib.color = RED;
359                         rotateLeft(sib);
360                         sib = x.p.left;
361                     }
362                     sib.color = x.p.color;
363                     x.p.color = BLACK;
364                     sib.left.color = BLACK;
365                     rotateRight(x.p);
366                     x = root;
367                 }
368             }
369         }
370
371         x.color = BLACK;
372     }
373     
374     protected void remove(Entry z) {
375         boolean isUnique = !( z.keyEquals(z.left) ||
376             z.keyEquals(z.right) || z.keyEquals(z.p) );
377         
378         Entry y = ( z.left != NIL && z.right != NIL ? successor(z) : z );
379         Entry x = ( y.left != NIL ? y.left : y.right );
380         x.p = y.p;
381         
382         if (y.p == NIL) {
383             root = x;
384         } else if (y == y.p.left) {
385             y.p.left = x;
386         } else {
387             y.p.right = x;
388         }
389         
390         if (y != z) {
391             z.copyFields(y);
392         }
393         if (y.color == BLACK)
394             fixUpRemove(x);
395         
396         decrementSize(isUnique);
397     }
398     
399     // ========================================================================
400
// Inner classes
401

402     // ------------------------------------------------------------------------
403
// Entry class - represents a Red-Black Tree Node
404

405     public static class Entry {
406         int val;
407         int order; // used to determine ordering for duplicate keys
408

409         Entry left = null;
410         Entry right = null;
411         Entry p;
412         boolean color = BLACK;
413         
414         public Entry(int val) {
415             this.val = val;
416         }
417         
418         public Entry(int val, Entry parent, int order) {
419             this.val = val;
420             this.p = parent;
421             this.order = order;
422             this.left = NIL;
423             this.right = NIL;
424         }
425         
426         public int getIntKey() {
427             throw new UnsupportedOperationException JavaDoc("Unsupported");
428         }
429         
430         public long getLongKey() {
431             throw new UnsupportedOperationException JavaDoc("Unsupported");
432         }
433         
434         public float getFloatKey() {
435             throw new UnsupportedOperationException JavaDoc("Unsupported");
436         }
437         
438         public double getDoubleKey() {
439             throw new UnsupportedOperationException JavaDoc("Unsupported");
440         }
441         
442         public Object JavaDoc getKey() {
443             return null;
444         }
445
446         public int getValue() {
447             return val;
448         }
449
450         public int getOrder() {
451             return order;
452         }
453         
454         public int setValue(int value) {
455             int old = val;
456             val = value;
457             return old;
458         }
459         
460         public boolean keyEquals(Entry e) {
461             Object JavaDoc k = getKey();
462             return ( k==null ? k==e.getKey() : k.equals(e.getKey()) );
463         }
464         
465         public boolean equals(Object JavaDoc o) {
466             if (!(o instanceof Entry))
467                 return false;
468             
469             Entry e = (Entry)o;
470             
471             return (val == e.val && getKey() == e.getKey());
472         }
473
474         public int hashCode() {
475             int khash = getKey().hashCode();
476             int vhash = val;
477             return khash^vhash;
478         }
479
480         public String JavaDoc toString() {
481             return getKey() + "=" + val;
482         }
483         
484         public void copyFields(Entry x) {
485             this.val = x.val;
486             this.order = x.order;
487         }
488         
489     }
490     
491     // ------------------------------------------------------------------------
492
// Iterators
493

494     protected class EntryIterator extends AbstractLiteralIterator {
495         private int expectedModCount = AbstractTreeMap.this.modCount;
496         private Entry lastReturned = NIL;
497         private boolean reverse = false;
498         Entry next, end;
499
500         EntryIterator(boolean reverse) {
501             next = reverse ? maximum(root) : minimum(root);
502             end = NIL;
503         }
504
505         EntryIterator(Entry first, Entry last) {
506             next = first;
507             end = last;
508             reverse = first==NIL ? true
509                     : last==NIL ? false
510                     : compare(first,last) > 0;
511         }
512
513         public boolean hasNext() {
514             return next != end;
515         }
516
517         final Entry nextEntry() {
518             if (!hasNext())
519                 throw new NoSuchElementException JavaDoc();
520             if (modCount != expectedModCount)
521                 throw new ConcurrentModificationException JavaDoc();
522             lastReturned = next;
523             next = reverse ? predecessor(next) : successor(next);
524             /// XXX DEBUG
525
if ( lastReturned == NIL ) {
526                 System.err.println("Encountered NIL in iteration!");
527             }
528             return lastReturned;
529         }
530
531         public Object JavaDoc next() {
532             return nextEntry();
533         }
534
535         public void remove() {
536             if (lastReturned == NIL)
537                 throw new IllegalStateException JavaDoc();
538             if (modCount != expectedModCount)
539                 throw new ConcurrentModificationException JavaDoc();
540             if (lastReturned.left != NIL && lastReturned.right != NIL)
541                 next = lastReturned;
542             AbstractTreeMap.this.remove(lastReturned);
543             ++expectedModCount;
544             lastReturned = NIL;
545         }
546     }
547
548     protected class KeyIterator extends EntryIterator {
549         public KeyIterator() {
550             super(false);
551         }
552         public KeyIterator(Entry start, Entry end) {
553             super(start, end);
554         }
555         public Object JavaDoc next() {
556             return nextEntry().getKey();
557         }
558     }
559
560     protected class ValueIterator extends IntIterator {
561         EntryIterator m_iter;
562         
563         public ValueIterator(EntryIterator iter) {
564             m_iter = iter;
565         }
566         public boolean hasNext() {
567             return m_iter.hasNext();
568         }
569         public int nextInt() {
570             return m_iter.nextEntry().val;
571         }
572         public void remove() {
573             m_iter.remove();
574         }
575     }
576         
577 } // end of abstract class AbstractTreeMap
578
Popular Tags