1
2
3
4
5
6
7
8
9
10
11 package nl.tudelft.simulation.dsol.eventlists;
12
13 import java.io.Serializable;
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.ConcurrentModificationException;
17 import java.util.Iterator;
18 import java.util.List;
19 import java.util.NoSuchElementException;
20 import nl.tudelft.simulation.dsol.formalisms.devs.SimEventInterface;
21
22 /***
23 * A RedBlackTree implementation of the eventlistInterface. This implementation
24 * is based on Java's TreeSet.
25 * <p>
26 * (c) copyright 2003 <a href="http://www.simulation.tudelft.nl">Delft
27 * University of Technology </a>, the Netherlands. <br>
28 * See for project information <a href="http://www.simulation.tudelft.nl">
29 * www.simulation.tudelft.nl </a> <br>
30 * License of use: <a href="http://www.gnu.org/copyleft/gpl.html">General Public
31 * License (GPL) </a>, no warranty <br>
32 *
33 * @author <a href="http://www.simulation.tudelft.nl/people/jacobs.html">Peter
34 * Jacobs </a>
35 * @version 1.4 2004-03-28
36 * @since 1.0
37 */
38 public class RedBlackTree implements EventListInterface
39 {
40 /*** the counter of events added to this list */
41 private static long counter = 0L;
42
43 /*** RED */
44 protected static final boolean RED = false;
45
46 /*** BLACK */
47 protected static final boolean BLACK = true;
48
49 /*** the root of the tree */
50 protected transient Entry root = null;
51
52 /*** The number of entries in the tree */
53 protected transient int size = 0;
54
55 /*** The number of structural modifications to the tree. */
56 protected transient int modCount = 0;
57
58 /***
59 * constructs a new RedBlackTree
60 */
61 public RedBlackTree()
62 {
63 super();
64 }
65
66 /***
67 * @see nl.tudelft.simulation.dsol.eventlists.EventListInterface
68 * #add(nl.tudelft.simulation.dsol.formalisms.devs.SimEventInterface)
69 */
70 public synchronized boolean add(final SimEventInterface event)
71 {
72 event.setID(RedBlackTree.counter++);
73 Entry entry = this.root;
74 if (entry == null)
75 {
76 this.incrementSize();
77 this.root = new Entry(event, null);
78 return true;
79 }
80 while (true)
81 {
82 int cmp = event.compareTo(entry.simEvent);
83 if (cmp == 0)
84 {
85 entry.simEvent = event;
86 return false;
87 } else if (cmp < 0)
88 {
89 if (entry.left != null)
90 {
91 entry = entry.left;
92 } else
93 {
94 this.incrementSize();
95 entry.left = new Entry(event, entry);
96 fixAfterInsertion(entry.left);
97 return true;
98 }
99 } else
100 {
101 if (entry.right != null)
102 {
103 entry = entry.right;
104 } else
105 {
106 incrementSize();
107 entry.right = new Entry(event, entry);
108 fixAfterInsertion(entry.right);
109 return true;
110 }
111 }
112 }
113 }
114
115 /***
116 * @see nl.tudelft.simulation.dsol.eventlists.EventListInterface
117 * #addAll(Collection)
118 */
119 public synchronized boolean addAll(final Collection collection)
120 {
121 for (Iterator iterator = collection.iterator(); iterator.hasNext();)
122 {
123 if (!this.add((SimEventInterface) iterator.next()))
124 {
125 return false;
126 }
127 }
128 return true;
129 }
130
131 /***
132 * @see nl.tudelft.simulation.dsol.eventlists.EventListInterface#clear()
133 */
134 public synchronized void clear()
135 {
136 this.modCount++;
137 this.size = 0;
138 this.root = null;
139 }
140
141 /***
142 * @see nl.tudelft.simulation.dsol.eventlists.EventListInterface
143 * #contains(nl.tudelft.simulation.dsol.formalisms.devs.SimEventInterface)
144 */
145 public synchronized boolean contains(final SimEventInterface event)
146 {
147 if (this.root == null)
148 {
149 return false;
150 }
151 if (event == null)
152 {
153 return this.eventSearchNull(this.root);
154 }
155 return this.eventSearchNonNull(this.root, event);
156 }
157
158 /***
159 * @see nl.tudelft.simulation.dsol.eventlists.EventListInterface
160 * #containsAll(Collection)
161 */
162 public synchronized boolean containsAll(final Collection collection)
163 {
164 for (Iterator iterator = collection.iterator(); iterator.hasNext();)
165 {
166 if (!this.contains((SimEventInterface) iterator.next()))
167 {
168 return false;
169 }
170 }
171 return true;
172 }
173
174 /***
175 * @see nl.tudelft.simulation.dsol.eventlists.EventListInterface #first()
176 */
177 public synchronized SimEventInterface first()
178 {
179 Entry first = this.firstEntry();
180 if (first == null)
181 {
182 return null;
183 }
184 return first.simEvent;
185 }
186
187 /***
188 * @see nl.tudelft.simulation.dsol.eventlists.EventListInterface#isEmpty()
189 */
190 public synchronized boolean isEmpty()
191 {
192 if (this.size == 0)
193 {
194 return true;
195 }
196 return false;
197 }
198
199 /***
200 * @see nl.tudelft.simulation.dsol.eventlists.EventListInterface #iterator()
201 */
202 public synchronized Iterator iterator()
203 {
204 return new EventListIterator();
205 }
206
207 /***
208 * @see nl.tudelft.simulation.dsol.eventlists.EventListInterface#last()
209 */
210 public synchronized SimEventInterface last()
211 {
212 Entry last = this.lastEntry();
213 if (last == null)
214 {
215 return null;
216 }
217 return last.simEvent;
218 }
219
220 /***
221 * @see nl.tudelft.simulation.dsol.eventlists.EventListInterface
222 * #remove(nl.tudelft.simulation.dsol.formalisms.devs.SimEventInterface)
223 */
224 public synchronized boolean remove(final SimEventInterface event)
225 {
226 Entry entry = getEntry(event);
227 if (entry == null)
228 {
229 return false;
230 }
231 this.deleteEntry(entry);
232 return true;
233 }
234
235 /***
236 * @see nl.tudelft.simulation.dsol.eventlists.EventListInterface#removeAll(Collection)
237 */
238 public synchronized boolean removeAll(final Collection collection)
239 {
240 for (Iterator iterator = collection.iterator(); iterator.hasNext();)
241 {
242 if (!this.remove((SimEventInterface) iterator.next()))
243 {
244 return false;
245 }
246 }
247 return true;
248 }
249
250 /***
251 * @see nl.tudelft.simulation.dsol.eventlists.EventListInterface
252 * #removeFirst()
253 */
254 public synchronized SimEventInterface removeFirst()
255 {
256 Entry entry = this.firstEntry();
257 this.deleteEntry(entry);
258 return entry.simEvent;
259 }
260
261 /***
262 * @see nl.tudelft.simulation.dsol.eventlists.EventListInterface#removeLast()
263 */
264 public synchronized SimEventInterface removeLast()
265 {
266 Entry entry = this.lastEntry();
267 this.deleteEntry(entry);
268 return entry.simEvent;
269 }
270
271 /***
272 * @see nl.tudelft.simulation.dsol.eventlists.EventListInterface#size()
273 */
274 public synchronized int size()
275 {
276 return this.size;
277 }
278
279 /***
280 * @see nl.tudelft.simulation.dsol.eventlists.EventListInterface #toArray()
281 */
282 public synchronized SimEventInterface[] toArray()
283 {
284 List result = new ArrayList();
285 for (Iterator i = this.iterator(); i.hasNext();)
286 {
287 result.add(i.next());
288 }
289 return (SimEventInterface[]) result
290 .toArray(new SimEventInterface[result.size()]);
291 }
292
293 /*** ********************** PRIVATE METHODS ******************************** */
294 /***
295 * decrements the size
296 */
297 private void decrementSize()
298 {
299 this.modCount++;
300 this.size--;
301 }
302
303 /***
304 * incrementSize
305 */
306 private void incrementSize()
307 {
308 this.modCount++;
309 this.size++;
310 }
311
312 /***
313 * returns the first entry from the RedBlackTree
314 *
315 * @return the first Entry
316 */
317 protected Entry firstEntry()
318 {
319 Entry entry = this.root;
320 if (entry != null)
321 {
322 while (entry.left != null)
323 {
324 entry = entry.left;
325 }
326 }
327 return entry;
328 }
329
330 /***
331 * returns the last entry from the RedBlackTree
332 *
333 * @return the last Entry
334 */
335 private Entry lastEntry()
336 {
337 Entry entry = this.root;
338 if (entry != null)
339 {
340 while (entry.right != null)
341 {
342 entry = entry.right;
343 }
344 }
345 return entry;
346 }
347
348 /***
349 * searches for nonnull events
350 *
351 * @param entry the entry to search
352 * @param event the event
353 * @return null?
354 */
355 private boolean eventSearchNonNull(final Entry entry,
356 final SimEventInterface event)
357 {
358 if (event.equals(entry.simEvent))
359 {
360 return true;
361 }
362
363 return (entry.left != null && eventSearchNonNull(entry.left, event))
364 || (entry.right != null && eventSearchNonNull(entry.right,
365 event));
366 }
367
368 /***
369 * searches for null events
370 *
371 * @param entry the entry to search
372 * @return null?
373 */
374 private boolean eventSearchNull(final Entry entry)
375 {
376 if (entry.simEvent == null)
377 {
378 return true;
379 }
380
381 return (entry.left != null && eventSearchNull(entry.left))
382 || (entry.right != null && eventSearchNull(entry.right));
383 }
384
385 /***
386 * returns the color of an entry
387 *
388 * @param entry the entry
389 * @return the color
390 */
391 private static boolean colorOf(final Entry entry)
392 {
393 if (entry == null)
394 {
395 return BLACK;
396 }
397 return entry.color;
398 }
399
400 /***
401 * returns the parent of p
402 *
403 * @param entry the entry
404 * @return Entry
405 */
406 private static Entry parentOf(final Entry entry)
407 {
408 if (entry == null)
409 {
410 return null;
411 }
412 return entry.parent;
413 }
414
415 /***
416 * sets the color of p
417 *
418 * @param entry the entry
419 * @param color the color
420 */
421 private static void setColor(final Entry entry, final boolean color)
422 {
423 if (entry != null)
424 {
425 entry.color = color;
426 }
427 }
428
429 /***
430 * returns the left child of entry
431 *
432 * @param entry the entry
433 * @return Entry
434 */
435 private static Entry leftOf(final Entry entry)
436 {
437 if (entry == null)
438 {
439 return null;
440 }
441 return entry.left;
442 }
443
444 /***
445 * returns the right entry of entry
446 *
447 * @param entry the entry
448 * @return Entry
449 */
450 private static Entry rightOf(final Entry entry)
451 {
452 if (entry == null)
453 {
454 return null;
455 }
456 return entry.right;
457 }
458
459 /***
460 * rotates left
461 *
462 * @param entry the entry to rotate
463 */
464 private void rotateLeft(final Entry entry)
465 {
466 Entry right = entry.right;
467 entry.right = right.left;
468 if (right.left != null)
469 {
470 right.left.parent = entry;
471 }
472 right.parent = entry.parent;
473 if (entry.parent == null)
474 {
475 this.root = right;
476 } else if (entry.parent.left == entry)
477 {
478 entry.parent.left = right;
479 } else
480 {
481 entry.parent.right = right;
482 }
483 right.left = entry;
484 entry.parent = right;
485 }
486
487 /***
488 * rotates to the right
489 *
490 * @param entry the entry to rotate
491 */
492 private void rotateRight(final Entry entry)
493 {
494 Entry left = entry.left;
495 entry.left = left.right;
496 if (left.right != null)
497 {
498 left.right.parent = entry;
499 }
500 left.parent = entry.parent;
501 if (entry.parent == null)
502 {
503 this.root = left;
504 } else if (entry.parent.right == entry)
505 {
506 entry.parent.right = left;
507 } else
508 {
509 entry.parent.left = left;
510 }
511 left.right = entry;
512 entry.parent = left;
513 }
514
515 /***
516 * fixes after insertion
517 *
518 * @param entry the entry
519 */
520 private void fixAfterInsertion(Entry entry)
521 {
522 entry.color = RED;
523 while (entry != null && entry != this.root && entry.parent.color == RED)
524 {
525 if (parentOf(entry) == leftOf(parentOf(parentOf(entry))))
526 {
527 Entry y = rightOf(parentOf(parentOf(entry)));
528 if (colorOf(y) == RED)
529 {
530 setColor(parentOf(entry), BLACK);
531 setColor(y, BLACK);
532 setColor(parentOf(parentOf(entry)), RED);
533 entry = parentOf(parentOf(entry));
534 } else
535 {
536 if (entry == rightOf(parentOf(entry)))
537 {
538 entry = parentOf(entry);
539 rotateLeft(entry);
540 }
541 setColor(parentOf(entry), BLACK);
542 setColor(parentOf(parentOf(entry)), RED);
543 if (parentOf(parentOf(entry)) != null)
544 {
545 rotateRight(parentOf(parentOf(entry)));
546 }
547 }
548 } else
549 {
550 Entry y = leftOf(parentOf(parentOf(entry)));
551 if (colorOf(y) == RED)
552 {
553 setColor(parentOf(entry), BLACK);
554 setColor(y, BLACK);
555 setColor(parentOf(parentOf(entry)), RED);
556 entry = parentOf(parentOf(entry));
557 } else
558 {
559 if (entry == leftOf(parentOf(entry)))
560 {
561 entry = parentOf(entry);
562 rotateRight(entry);
563 }
564 setColor(parentOf(entry), BLACK);
565 setColor(parentOf(parentOf(entry)), RED);
566 if (parentOf(parentOf(entry)) != null)
567 {
568 rotateLeft(parentOf(parentOf(entry)));
569 }
570 }
571 }
572 }
573 this.root.color = BLACK;
574 }
575
576 /***
577 * deletes entry , and then rebalance the tree.
578 *
579 * @param entry entry
580 */
581 protected void deleteEntry(Entry entry)
582 {
583 this.decrementSize();
584
585
586
587 if (entry.left != null && entry.right != null)
588 {
589 Entry s = successor(entry);
590 entry.simEvent = s.simEvent;
591 entry = s;
592 }
593
594 Entry replacement = entry.left;
595 if (replacement == null)
596 {
597 replacement = entry.right;
598 }
599 if (replacement != null)
600 {
601
602 replacement.parent = entry.parent;
603 if (entry.parent == null)
604 {
605 this.root = replacement;
606 } else if (entry == entry.parent.left)
607 {
608 entry.parent.left = replacement;
609 } else
610 {
611 entry.parent.right = replacement;
612 }
613
614 entry.left = null;
615 entry.right = null;
616 entry.parent = null;
617
618 if (entry.color == BLACK)
619 {
620 fixAfterDeletion(replacement);
621 }
622 } else if (entry.parent == null)
623 {
624 this.root = null;
625 } else
626 {
627 if (entry.color == BLACK)
628 {
629 fixAfterDeletion(entry);
630 }
631 if (entry.parent != null)
632 {
633 if (entry == entry.parent.left)
634 {
635 entry.parent.left = null;
636 } else if (entry == entry.parent.right)
637 {
638 entry.parent.right = null;
639 }
640 entry.parent = null;
641 }
642 }
643 }
644
645 /***
646 * fixes after deletion
647 *
648 * @param entry the entry
649 */
650 private void fixAfterDeletion(Entry entry)
651 {
652 while (entry != this.root && colorOf(entry) == BLACK)
653 {
654 if (entry == leftOf(parentOf(entry)))
655 {
656 Entry sib = rightOf(parentOf(entry));
657 if (colorOf(sib) == RED)
658 {
659 setColor(sib, BLACK);
660 setColor(parentOf(entry), RED);
661 rotateLeft(parentOf(entry));
662 sib = rightOf(parentOf(entry));
663 }
664 if (colorOf(leftOf(sib)) == BLACK
665 && colorOf(rightOf(sib)) == BLACK)
666 {
667 setColor(sib, RED);
668 entry = parentOf(entry);
669 } else
670 {
671 if (colorOf(rightOf(sib)) == BLACK)
672 {
673 setColor(leftOf(sib), BLACK);
674 setColor(sib, RED);
675 rotateRight(sib);
676 sib = rightOf(parentOf(entry));
677 }
678 setColor(sib, colorOf(parentOf(entry)));
679 setColor(parentOf(entry), BLACK);
680 setColor(rightOf(sib), BLACK);
681 rotateLeft(parentOf(entry));
682 entry = this.root;
683 }
684 } else
685 {
686 Entry sib = leftOf(parentOf(entry));
687 if (colorOf(sib) == RED)
688 {
689 setColor(sib, BLACK);
690 setColor(parentOf(entry), RED);
691 rotateRight(parentOf(entry));
692 sib = leftOf(parentOf(entry));
693 }
694 if (colorOf(rightOf(sib)) == BLACK
695 && colorOf(leftOf(sib)) == BLACK)
696 {
697 setColor(sib, RED);
698 entry = parentOf(entry);
699 } else
700 {
701 if (colorOf(leftOf(sib)) == BLACK)
702 {
703 setColor(rightOf(sib), BLACK);
704 setColor(sib, RED);
705 rotateLeft(sib);
706 sib = leftOf(parentOf(entry));
707 }
708 setColor(sib, colorOf(parentOf(entry)));
709 setColor(parentOf(entry), BLACK);
710 setColor(leftOf(sib), BLACK);
711 rotateRight(parentOf(entry));
712 entry = this.root;
713 }
714 }
715 }
716 setColor(entry, BLACK);
717 }
718
719 /***
720 * gets the entry
721 *
722 * @param event the event
723 * @return Entry the entry
724 */
725 private Entry getEntry(final SimEventInterface event)
726 {
727 Entry entry = this.root;
728 while (entry != null)
729 {
730 int cmp = event.compareTo(entry.simEvent);
731 if (cmp < 0)
732 {
733 entry = entry.left;
734 } else if (cmp > 0)
735 {
736 entry = entry.right;
737 } else if (cmp == 0)
738 {
739 return entry;
740 }
741 }
742 return null;
743 }
744
745 /***
746 * Returns the successor of the specified Entry, or null if no such.
747 *
748 * @param entry the entry
749 * @return Entry the successor
750 */
751 protected Entry successor(final Entry entry)
752 {
753 if (entry == null)
754 {
755 return null;
756 } else if (entry.right != null)
757 {
758 Entry right = entry.right;
759 while (right.left != null)
760 {
761 right = right.left;
762 }
763 return right;
764 } else
765 {
766 Entry right = entry.parent;
767 Entry ch = entry;
768 while (right != null && ch == right.right)
769 {
770 ch = right;
771 right = right.parent;
772 }
773 return right;
774 }
775 }
776
777 /***
778 * A Entry <br>
779 * (c) copyright 2003 <a href="http://www.simulation.tudelft.nl">Delft
780 * University of Technology </a>, the Netherlands. <br>
781 * See for project information <a
782 * href="http://www.simulation.tudelft.nl">www.simulation.tudelft.nl </a>
783 * <br>
784 * License of use: <a href="http://www.gnu.org/copyleft/gpl.html">General
785 * Public License (GPL) </a>, no warranty <br>
786 *
787 * @version 1.0 Feb 24, 2004 <br>
788 * @author <a
789 * href="http://www.simulation.tudelft.nl/people/jacobs.html">Peter
790 * Jacobs </a>
791 */
792 private static class Entry implements Serializable
793 {
794 /*** the simEvent stored in the entry */
795 protected SimEventInterface simEvent = null;
796
797 /*** the left entry */
798 protected Entry left = null;
799
800 /*** the right entry */
801 protected Entry right = null;
802
803 /*** the parent */
804 protected Entry parent = null;
805
806 /*** the color of the entry */
807 protected boolean color = BLACK;
808
809 /***
810 * constructs a new Entry
811 */
812 public Entry()
813 {
814 super();
815 }
816
817 /***
818 * constructs a new Entry
819 *
820 * @param simEvent the simEvent of the entry
821 */
822 public Entry(final SimEventInterface simEvent)
823 {
824 this();
825 this.simEvent = simEvent;
826 }
827
828 /***
829 * constructs a new Entry
830 *
831 * @param simEvent the simEvent of the entry
832 * @param parent the parent
833 */
834 public Entry(final SimEventInterface simEvent, final Entry parent)
835 {
836 this(simEvent);
837 this.parent = parent;
838 }
839
840 /***
841 * constructs a new Entry
842 *
843 * @param simEvent the simEvent of the entry
844 * @param parent the parent
845 * @param left the left child
846 * @param right the right child
847 */
848 public Entry(final SimEventInterface simEvent, final Entry parent,
849 final Entry left, final Entry right)
850 {
851 this(simEvent, parent);
852 this.left = left;
853 this.right = right;
854 }
855 }
856 /***
857 * A EntryIterator <br>
858 * (c) copyright 2003 <a href="http://www.simulation.tudelft.nl">Delft
859 * University of Technology </a>, the Netherlands. <br>
860 * See for project information <a
861 * href="http://www.simulation.tudelft.nl">www.simulation.tudelft.nl </a>
862 * <br>
863 * License of use: <a href="http://www.gnu.org/copyleft/gpl.html">General
864 * Public License (GPL) </a>, no warranty <br>
865 *
866 * @version 1.0 Feb 16, 2004 <br>
867 * @author <a href="http://www.simulation.tudelft.nl/people/jacobs.html">
868 * Peter Jacobs </a>
869 */
870 private class EntryIterator implements Iterator
871 {
872 /*** the expectedModCount */
873 protected int expectedModCount = RedBlackTree.this.modCount;
874
875 /*** the event of the lastReturned entry */
876 protected Entry lastReturned = null;
877
878 /*** the event of the next entry */
879 protected Entry next = null;
880
881 /***
882 * constructs a new EntryIterator
883 */
884 public EntryIterator()
885 {
886 this.next = firstEntry();
887 }
888
889 /***
890 * constructs a new EntryIterator
891 *
892 * @param first the starting point
893 */
894 public EntryIterator(final Entry first)
895 {
896 this.next = first;
897 }
898
899 /***
900 * @see java.util.Iterator#hasNext()
901 */
902 public boolean hasNext()
903 {
904 return this.next != null;
905 }
906
907 /***
908 * @return the next Entry
909 */
910 public final Entry nextEntry()
911 {
912 if (this.next == null)
913 {
914 throw new NoSuchElementException();
915 }
916 if (RedBlackTree.this.modCount != this.expectedModCount)
917 {
918 throw new ConcurrentModificationException();
919 }
920 this.lastReturned = this.next;
921 this.next = successor(this.next);
922 return this.lastReturned;
923 }
924
925 /***
926 * @see java.util.Iterator#next()
927 */
928 public Object next()
929 {
930 return this.nextEntry();
931 }
932
933 /***
934 * @see java.util.Iterator#remove()
935 */
936 public void remove()
937 {
938 if (this.lastReturned == null)
939 {
940 throw new IllegalStateException();
941 }
942 if (RedBlackTree.this.modCount != this.expectedModCount)
943 {
944 throw new ConcurrentModificationException();
945 }
946 if (this.lastReturned.left != null
947 && this.lastReturned.right != null)
948 {
949 this.next = this.lastReturned;
950 }
951 deleteEntry(this.lastReturned);
952 this.expectedModCount++;
953 this.lastReturned = null;
954 }
955 }
956 /***
957 * A EventListIterator <br>
958 * (c) copyright 2003 <a href="http://www.simulation.tudelft.nl">Delft
959 * University of Technology </a>, the Netherlands. <br>
960 * See for project information <a
961 * href="http://www.simulation.tudelft.nl">www.simulation.tudelft.nl </a>
962 * <br>
963 * License of use: <a href="http://www.gnu.org/copyleft/gpl.html">General
964 * Public License (GPL) </a>, no warranty <br>
965 *
966 * @version 1.0 Feb 16, 2004 <br>
967 * @author <a href="http://www.simulation.tudelft.nl/people/jacobs.html">
968 * Peter Jacobs </a>
969 */
970 private class EventListIterator extends EntryIterator
971 {
972 /***
973 * constructs a new EventListIterator
974 */
975 public EventListIterator()
976 {
977 super();
978 }
979
980 /***
981 * @see java.util.Iterator#next()
982 */
983 public Object next()
984 {
985 return ((Entry) super.next()).simEvent;
986 }
987 }
988 }