SSJ API Documentation
Stochastic Simulation in Java
Loading...
Searching...
No Matches
SplayTree.java
1/*
2 * Class: SplayTree
3 * Description: implementation of class EventList using a splay tree
4 * Environment: Java
5 * Software: SSJ
6 * Copyright (C) 2001 Pierre L'Ecuyer and Universite de Montreal
7 * Organization: DIRO, Universite de Montreal
8 * @author
9 * @since
10 *
11 *
12 * Licensed under the Apache License, Version 2.0 (the "License");
13 * you may not use this file except in compliance with the License.
14 * You may obtain a copy of the License at
15 *
16 * http://www.apache.org/licenses/LICENSE-2.0
17 *
18 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 * See the License for the specific language governing permissions and
22 * limitations under the License.
23 *
24 */
25package umontreal.ssj.simevents.eventlist;
26
27import java.util.Iterator;
28import java.util.ListIterator;
29import java.util.ConcurrentModificationException;
30import java.util.NoSuchElementException;
31import umontreal.ssj.util.PrintfFormat;
32import umontreal.ssj.simevents.Event;
33
46public class SplayTree implements EventList {
47 private Entry root = null;
48 private int modCount = 0;
49
50 private int myCompareTo(Event ev, Event other) {
51 // A new event must always occur after those with the same time and
52 // same priority in the Event list. getRa is used to ensure that.
53 int j = ev.compareTo(other);
54 if (0 != j)
55 return j;
56 if (ev.getRa() < other.getRa())
57 return -1;
58 if (ev.getRa() > other.getRa())
59 return 1;
60 return 0;
61 }
62
63 public boolean isEmpty() {
64 return root == null;
65 }
66
67 public void clear() {
68 // Simply root = null would be more efficient but the
69 // entries would not be recuperated.
70 while (root != null)
71 remove(root);
72 }
73
74 public void add(Event ev) {
75 // ajoute un element dans l'arbre en faisant un "splay"
76
77 // reference pour le splay :
78 // WEISS, Mark Allen, Data Structures & Problem Solving using JAVA
79 // section 22.5 Top-Down Splay Tree
80
81 // "zig" : rotation entre un element et son parent
82 // "zig-zag" simplifie : rotation entre un element et son parent
83 // "zig-zig" : rotation entre le parent et le grand-parent,
84 // suivis par une rotation entre le parent et l'element
85
86 // NOTE : on considere toujours qu'un nouvel element doit etre place
87 // apres les evenements de meme temps et meme priorite
88
89 ev.setRa(1); // Temporary; make sure ev is after other events with
90 // the same time and priority. Others have ra = 0.
91
92 Entry next = root;
93 // le nouvel evenement devient la racine
94 Entry e = add(ev, null);
95 root = e;
96 if (next != null) {
97 Entry left = root;
98 Entry right = root;
99 Entry temp = null;
100 boolean end_splay = false;
101 while (!end_splay) {
102 if (myCompareTo(ev, next.event) > 0) {
103 temp = next.right;
104 if (temp == null) {
105 // cas "zig"
106 left.right = next;
107 next.father = left;
108 right.left = null;
109 end_splay = true;
110 } else if (myCompareTo(ev, temp.event) < 0) {
111 // cas "zig-zag" simplifie
112 left.right = next;
113 next.father = left;
114 left = next;
115 next = temp;
116 } else {
117 // cas "zig-zig"
118 next.right = temp.left;
119 if (temp.left != null)
120 temp.left.father = next;
121 left.right = temp;
122 temp.father = left;
123 temp.left = next;
124 next.father = temp;
125 left = temp;
126 next = temp.right;
127 if (next == null) {
128 right.left = null;
129 end_splay = true;
130 }
131 }
132
133 } else {
134 temp = next.left;
135 if (temp == null) {
136 // cas "zig"
137 right.left = next;
138 next.father = right;
139 left.right = null;
140 end_splay = true;
141 } else if (myCompareTo(ev, temp.event) > 0) {
142 // cas "zig-zag" simplifie
143 right.left = next;
144 next.father = right;
145 right = next;
146 next = temp;
147 } else {
148 // cas "zig-zig"
149 next.left = temp.right;
150 if (temp.right != null)
151 temp.right.father = next;
152 right.left = temp;
153 temp.father = right;
154 temp.right = next;
155 next.father = temp;
156 right = temp;
157 next = temp.left;
158 if (next == null) {
159 left.right = null;
160 end_splay = true;
161 }
162 }
163 }
164 }
165 temp = e.left;
166 e.left = e.right;
167 e.right = temp;
168 }
169 ev.setRa(0);
170 ++modCount;
171 }
172
173 public void addFirst(Event ev) {
174 if (root == null)
175 root = add(ev, null);
176 else {
177 Entry cursor = root;
178 while (cursor.left != null)
179 cursor = cursor.left;
180 cursor.left = add(ev, cursor);
181 }
182 ++modCount;
183 }
184
185 public void addBefore(Event ev, Event other) {
186 Entry otherEntry = findEntry(other);
187 if (otherEntry == null)
188 throw new IllegalArgumentException("Event not in list.");
189
190 Entry e = add(ev, null);
191 // insere e a la place de otherEntry et otherEntry
192 // devient le fils droit de e
193 if (otherEntry != root) {
194 if (otherEntry == otherEntry.father.left)
195 otherEntry.father.left = e;
196 else
197 otherEntry.father.right = e;
198 } else
199 root = e;
200 e.father = otherEntry.father;
201 otherEntry.father = e;
202 e.right = otherEntry;
203 // le sous-arbre de droite de otherEntry devient le sous-arbre de
204 // droite de e.
205 // permet que e soit exactement apres otherEntry qu'importe
206 // les operations effectuees
207 e.left = otherEntry.left;
208 if (e.left != null)
209 e.left.father = e;
210 otherEntry.left = null;
211 ++modCount;
212 }
213
214 public void addAfter(Event ev, Event other) {
215 Entry otherEntry = findEntry(other);
216 if (otherEntry == null)
217 throw new IllegalArgumentException("Event not in list.");
218 Entry e = add(ev, otherEntry);
219 // insere e comme fils droit de otherEntry
220 e.right = otherEntry.right;
221 otherEntry.right = e;
222 if (e.right != null)
223 e.right.father = e;
224 ++modCount;
225 }
226
227 public Event getFirst() {
228 if (root == null)
229 return null;
230 Entry cursor = root;
231 while (cursor.left != null)
232 cursor = cursor.left;
233 return cursor.event;
234 }
235
236 public Event getFirstOfClass(String cl) {
237 Entry cursor = root;
238 if (root != null)
239 while (cursor.left != null)
240 cursor = cursor.left;
241 while (cursor != null) {
242 if (cursor.event.getClass().getName().equals(cl))
243 return cursor.event;
244 cursor = successor(cursor);
245 }
246 return null;
247 }
248
249 @SuppressWarnings("unchecked")
250
251 public <E extends Event> E getFirstOfClass(Class<E> cl) {
252 Entry cursor = root;
253 if (root != null)
254 while (cursor.left != null)
255 cursor = cursor.left;
256 while (cursor != null) {
257 if (cursor.event.getClass() == cl)
258 return (E) cursor.event;
259 cursor = successor(cursor);
260 }
261 return null;
262 }
263
264 public Iterator<Event> iterator() {
265 return listIterator();
266 }
267
268 public ListIterator<Event> listIterator() {
269 return new SPItr();
270 }
271
272 public boolean remove(Event ev) {
273 // on trouve le noeud correspondant a l'evenement pour l'enlever
274 if (root == null)
275 return false;
276 Entry e = findEntry(ev);
277 if (e == null)
278 return false;
279 return remove(e);
280 }
281
283 if (root == null)
284 return null;
285 Entry cursor = root;
286 while (cursor.left != null)
287 cursor = cursor.left;
288 Event first = cursor.event;
289 remove(cursor);
290 return first;
291 }
292
293 public String toString() {
294 StringBuilder sb = new StringBuilder("Contents of the event list SplayTree:");
295 Entry cursor = root;
296 if (root != null)
297 while (cursor.left != null)
298 cursor = cursor.left;
299 while (cursor != null) {
300 sb.append(PrintfFormat.NEWLINE + PrintfFormat.g(12, 7, cursor.event.time()) + ", "
301 + PrintfFormat.g(8, 4, cursor.event.priority()) + " : " + cursor.event.toString());
302 cursor = successor(cursor);
303 }
304 return sb.toString();
305 }
306
307 private static class Entry {
308 Event event;
309 Entry father;
310 Entry left;
311 Entry right;
312
313 Entry(Event event, Entry left, Entry right, Entry father) {
314 this.event = event;
315 this.left = left;
316 this.right = right;
317 this.father = father;
318 }
319 }
320
321 private class SPItr implements ListIterator<Event> {
322 private Entry prev;
323 private Entry next;
324 private Entry lastRet;
325 private int expectedModCount;
326 private int nextIndex;
327
328 SPItr() {
329 prev = null;
330 next = root;
331 if (next != null) {
332 while (next.left != null)
333 next = next.left;
334 }
335 expectedModCount = modCount;
336 lastRet = null;
337 nextIndex = 0;
338 }
339
340 public void add(Event ev) {
341 if (modCount != expectedModCount)
342 throw new ConcurrentModificationException();
343
344 // Check the event time and priority
345 if (next != null && ev.compareTo(next.event) > 0) {
346 ev.setTime(next.event.time());
347 ev.setPriority(next.event.priority());
348 }
349 if (prev != null && ev.compareTo(prev.event) < 0) {
350 ev.setTime(prev.event.time());
351 ev.setPriority(prev.event.priority());
352 }
353
354 Entry e = SplayTree.this.add(ev, null);
355 if (prev != null) {
356 // Ajouter ev apr`es prev.
357 // insere e comme fils droit de prev
358 e.father = prev;
359 e.right = prev.right;
360 prev.right = e;
361 if (e.right != null)
362 e.right.father = e;
363 } else {
364 // ajoute ev avant next.
365 // insere e a la place de otherEntry et
366 // otherEntry devient le fils droit de e
367 if (next != root) {
368 if (next == next.father.left)
369 next.father.left = e;
370 else
371 next.father.right = e;
372 } else
373 root = e;
374 e.father = next.father;
375 next.father = e;
376 e.right = next;
377 // le sous-arbre de droite de otherEntry
378 // devient le sous-arbre de droite de e.
379 // permet que e soit exactement apres otherEntry qu'importe les
380 // operations effectuees
381 e.left = next.left;
382 if (e.left != null)
383 e.left.father = e;
384 next.left = null;
385 }
386
387 prev = e;
388 ++nextIndex;
389 lastRet = null;
390 ++modCount;
391 ++expectedModCount;
392 }
393
394 public boolean hasNext() {
395 if (modCount != expectedModCount)
396 throw new ConcurrentModificationException();
397 return next != null;
398 }
399
400 public boolean hasPrevious() {
401 if (modCount != expectedModCount)
402 throw new ConcurrentModificationException();
403 return prev != null;
404 }
405
406 public Event next() {
407 if (!hasNext())
408 throw new NoSuchElementException();
409
410 ++nextIndex;
411 Event ev = next.event;
412 lastRet = next;
413 prev = next;
414 next = successor(next);
415 return ev;
416 }
417
418 public int nextIndex() {
419 if (!hasNext())
420 throw new NoSuchElementException();
421
422 return nextIndex;
423 }
424
425 public Event previous() {
426 if (!hasPrevious())
427 throw new NoSuchElementException();
428
429 --nextIndex;
430 Event ev = prev.event;
431 lastRet = prev;
432 next = prev;
433 prev = predecessor(prev);
434 return ev;
435 }
436
437 public int previousIndex() {
438 if (!hasPrevious())
439 throw new NoSuchElementException();
440
441 return nextIndex - 1;
442 }
443
444 public void remove() {
445 if (modCount != expectedModCount)
446 throw new ConcurrentModificationException();
447 if (lastRet == null)
448 throw new IllegalStateException();
449
450 if (lastRet == next) // Last call to previous
451 next = successor(next);
452 else { // Last call to next or no call
453 prev = predecessor(prev);
454 --nextIndex;
455 }
456 SplayTree.this.remove(lastRet);
457 lastRet = null;
458 ++expectedModCount;
459 }
460
461 public void set(Event ev) {
462 if (modCount != expectedModCount)
463 throw new ConcurrentModificationException();
464 if (lastRet == null)
465 throw new IllegalStateException();
466
467 Entry pred = predecessor(lastRet);
468 Entry succ = successor(lastRet);
469
470 if (pred != null && ev.compareTo(pred.event) < 0) {
471 ev.setTime(pred.event.time());
472 ev.setPriority(pred.event.priority());
473 }
474 if (succ != null && ev.compareTo(succ.event) > 0) {
475 ev.setTime(succ.event.time());
476 ev.setPriority(succ.event.priority());
477 }
478
479 lastRet.event = ev;
480 }
481 }
482
486 private Entry add(Event ev, Entry father) {
487 return new Entry(ev, null, null, father);
488 }
489
490 /*
491 * Remonte a la racine une entree avec un splay de type "bottom-up", qui prend
492 * pour parametre le noeud a remonter.
493 *
494 * Fonctionnement du splay : Jusqu'a ce que l'element devienne la racine, on
495 * fait : - Si le pere de l'element est la racine, on fait la rotation entre le
496 * pere et l'element (cas "zig"). - Si le pere de l'element et l'element ne sont
497 * pas des fils du meme cote (gauche-droite ou droite-gauche), alors on fait la
498 * rotation entre le pere et l'element (cas "zig-zag" simplifie). - Si le pere
499 * de l'element et l'element sont des fils du meme cote (gauche-gauche ou
500 * droite-droite), alors on fait la rotation entre le grand-pere et le pere
501 * avant de faire la rotation entre le pere et l'element (cas "zig-zig").
502 */
503 private void splay(Entry e) {
504 boolean left;
505
506 Entry f; // = father le pere de l'element e
507 Entry gf; // = grandFather le grand-pere de l'element e
508 Entry ggf; // = grandGrandFather l'arriere-grand-pere de l'element e
509
510 while (e.father != null) {
511 f = e.father;
512 gf = f.father;
513 left = e == f.left;
514
515 if (left)
516 // cas du fils gauche
517 if (gf == null) {
518 // cas "zig", on fait la rotation de f (la racine) et e
519 f.father = e;
520 f.left = e.right;
521 if (f.left != null)
522 f.left.father = f;
523 e.right = f;
524 e.father = null;
525 } else if (gf.right == f) {
526 // cas "zig-zag", simplifie, pareil que le cas "zig"
527 gf.right = e;
528
529 f.father = e;
530 f.left = e.right;
531 if (f.left != null)
532 f.left.father = f;
533 e.right = f;
534 e.father = gf;
535 } else {
536 // cas "zig-zig", on fait la rotation de gf avec
537 // f, suivis de la rotation de e avec f
538 ggf = gf.father;
539
540 gf.left = f.right;
541 if (gf.left != null)
542 gf.left.father = gf;
543 f.right = gf;
544 gf.father = f;
545
546 f.left = e.right;
547 if (f.left != null)
548 f.left.father = f;
549 f.father = e;
550 e.right = f;
551
552 // on rattache e a son nouveau pere
553 e.father = ggf;
554 if (ggf != null)
555 if (ggf.left == gf)
556 ggf.left = e;
557 else
558 ggf.right = e;
559 }
560 else
561 // cas du fils droit
562 if (gf == null) {
563 // cas "zig", on fait la rotation de f (la racine) et e
564
565 f.father = e;
566 f.right = e.left;
567 if (f.right != null)
568 f.right.father = f;
569 e.left = f;
570 e.father = null;
571 } else if (gf.left == f) {
572 // cas "zig-zag", simplifie, pareil que le cas "zig"
573 gf.left = e;
574
575 f.father = e;
576 f.right = e.left;
577 if (f.right != null)
578 f.right.father = f;
579 e.left = f;
580 e.father = gf;
581 } else {
582 // cas "zig-zig", on fait la rotation de gf avec
583 // f, suivis de la rotation de e avec f
584 ggf = gf.father;
585
586 gf.right = f.left;
587 if (gf.right != null)
588 gf.right.father = gf;
589 f.left = gf;
590 gf.father = f;
591
592 f.right = e.left;
593 if (f.right != null)
594 f.right.father = f;
595 f.father = e;
596 e.left = f;
597
598 // on rattache e a son nouveau pere
599 e.father = ggf;
600 if (ggf != null)
601 if (ggf.left == gf)
602 ggf.left = e;
603 else
604 ggf.right = e;
605 }
606 }
607 }
608
624 private boolean remove(Entry e) {
625 if (root == null || e == null)
626 return false;
627
628 splay(e);
629 // e est implicitement la racine, meme si root != e
630
631 Entry leftTree = e.left;
632 Entry rightTree = e.right;
633
634 if (leftTree != null)
635 leftTree.father = null;
636 if (rightTree != null)
637 rightTree.father = null;
638
639 e.left = null;
640 e.event = null;
641 e.right = null;
642
643 if (rightTree == null)
644 root = leftTree;
645 else if (leftTree == null)
646 root = rightTree;
647 else {
648 // on cherche le plus petit element du sous-arbre de droite
649 Entry newRoot = rightTree;
650 while (newRoot.left != null)
651 newRoot = newRoot.left;
652
653 // on monte newRoot en haut du sous-arbre de droite
654 splay(newRoot);
655
656 // on rattache les deux sous-arbres
657 newRoot.left = leftTree;
658 leftTree.father = newRoot;
659 root = newRoot;
660 }
661
662 ++modCount;
663
664 return true;
665 }
666
670 private Entry findEntry(Event ev) {
671 Entry cursor = root;
672 while (cursor != null) {
673 if (cursor.event == ev)
674 return cursor;
675 else if (ev.compareTo(cursor.event) > 0)
676 cursor = cursor.right;
677 else if (ev.compareTo(cursor.event) < 0)
678 cursor = cursor.left;
679 else {
680 // on a trouve un element "egal" (compareTo() revoie 0 ), on ne peut donc plus
681 // utiliser la recherche binaire et il faut donc regarder
682 // tous les elements "egaux" qui se retrouvent soit apres,
683 // soit avant l'element trouve
684 Entry center = cursor;
685
686 // recherche avant center
687 while (cursor != null && ev.compareTo(cursor.event) == 0)
688 if (cursor.event == ev)
689 return cursor;
690 else
691 cursor = predecessor(cursor);
692
693 cursor = center;
694
695 // recherche apres center
696 while (cursor != null && ev.compareTo(cursor.event) == 0)
697 if (cursor.event == ev)
698 return cursor;
699 else
700 cursor = successor(cursor);
701
702 return null;
703 }
704 }
705 return null;
706 }
707
708 private Entry successor(Entry cursor) {
709 if (cursor == null)
710 return null;
711
712 if (cursor.right != null) {
713 cursor = cursor.right;
714 while (cursor.left != null)
715 cursor = cursor.left;
716 } else {
717 while (cursor.father != null && cursor.father.right == cursor)
718 cursor = cursor.father;
719 cursor = cursor.father;
720 }
721 return cursor;
722 }
723
724 private Entry predecessor(Entry cursor) {
725 if (cursor == null)
726 return null;
727
728 if (cursor.left != null) {
729 cursor = cursor.left;
730 while (cursor.right != null)
731 cursor = cursor.right;
732 } else {
733
734 while (cursor.father != null && cursor.father.left == cursor)
735 cursor = cursor.father;
736 cursor = cursor.father;
737 }
738 return cursor;
739 }
740
741 /*
742 * public static void main (String[] args) { SplayTree sp = new SplayTree();
743 * Event1 e1 = new Event1(); e1.setTime(10.0); Event1 e2 = new Event1();
744 * e2.setTime(20.0); Event1 e3 = new Event1(); e3.setTime(30.0); Event1 e4 = new
745 * Event1(); e4.setTime(40.0); Event1 e5 = new Event1(); e5.setTime(50.0);
746 * Event1 e6 = new Event1(); e6.setTime(60.0); Event1 e7 = new Event1();
747 * e7.setTime(70.0); sp.add(e1); sp.add(e2); sp.print2(sp.root); sp.add(e3);
748 * sp.print2(sp.root); sp.add(e4); sp.print2(sp.root); sp.add(e5);
749 * sp.print2(sp.root); sp.add(e6); sp.print2(sp.root); sp.add(e7);
750 * sp.print2(sp.root); sp.add(e5); sp.print2(sp.root); sp.add(e7);
751 * sp.print2(sp.root); sp.add(e5); sp.print2(sp.root);
752 *
753 * sp.getFirst(); System.out.println(".....after Get" + PrintfFormat.NEWLINE +
754 * PrintfFormat.NEWLINE + PrintfFormat.NEWLINE); sp.print2(sp.root);
755 * sp.remove(e3); System.out.println("Apres remove" + PrintfFormat.NEWLINE);
756 * sp.print2(sp.root); }
757 *
758 * private void print(Entry t) { if (t != null){ print (t.left);
759 * System.out.println ("===========> Event time "+t.event.time()); print
760 * (t.right); } }
761 *
762 * private void print2(Entry t) {
763 * System.out.println("=============================== "+
764 * "print2 : pour ..... "+t.event.time()); if (t != null) { System.out.println
765 * ("===========> ev time "+t.event.time()); gauche (t.left); droite
766 * (t.right); System.out.println(); } else System.out.println
767 * ("===========> gauche null "); }
768 *
769 * private void gauche (Entry t) { if (t != null) { System.out.println
770 * ("===========> gauche "+t.event.time()); gauche (t.left); droite (t.right);
771 * System.out.println(); } else System.out.println
772 * ("===========> gauche null "); }
773 *
774 * private void droite (Entry t) { if (t != null){ System.out.println
775 * ("===========> droite "+t.event.time()); gauche (t.left); droite (t.right);
776 * // System.out.println(); } else System.out.println
777 * ("===========> droite null "); }
778 *
779 * private static class Event1 extends Event { public void actions() {}
780 *
781 * public String toString() { return "Event(" + eventTime + ")"; } }
782 */
783}
This abstract class provides event scheduling tools.
Definition Event.java:53
int compareTo(Event e)
Compares this object with the specified object e for order.
Definition Event.java:325
An implementation of EventList using a splay tree.
Event getFirst()
Returns the first event in the event list.
Event getFirstOfClass(String cl)
Returns the first event of the class cl (a subclass of Event) in the event list.
void addAfter(Event ev, Event other)
Same as add, but adds the new event ev immediately after the event other in the list.
void addBefore(Event ev, Event other)
Same as add, but adds the new event ev immediately before the event other in the list.
boolean isEmpty()
Returns true if and only if the event list is empty (no event is scheduled).
ListIterator< Event > listIterator()
Returns a list iterator over the elements of the class Event in this list.
void clear()
Empties the event list, i.e., cancels all events.
Event removeFirst()
Removes the first event from the event list (to cancel or execute this event).
void addFirst(Event ev)
Adds a new event at the beginning of the event list.
void add(Event ev)
Adds a new event in the event list, according to the time of ev.
This class acts like a StringBuffer which defines new types of append methods.
static final String NEWLINE
End-of-line symbol or line separator.
static String g(double x)
Same as g(0, 6, x).
An interface for implementations of event lists.