node) {
85 | if (node == null)
86 | return 0;
87 | return (1 + Math.max(treeHeight(node.left), treeHeight(node.right)));
88 | }
89 |
90 | public int rotations() {
91 | return rotations;
92 | }
93 |
94 | public String toString() {
95 | return "AVL tree (no parent ref., no recursion) of size: " + size + ", height: " + treeHeight() + ", rotations "
96 | + rotations;
97 | }
98 |
99 | /**
100 | * Returns the number of key-value mappings in this map.
101 | *
102 | * @return the number of key-value mappings in this map
103 | */
104 | public int size() {
105 | return size;
106 | }
107 |
108 | /**
109 | * Returns the value to which the specified key is mapped,
110 | * or {@code null} if this map contains no mapping for the key.
111 | *
112 | * More formally, if this map contains a mapping from a key
113 | * {@code k} to a value {@code v} such that {@code key} compares
114 | * equal to {@code k} according to the map's ordering, then this
115 | * method returns {@code v}; otherwise it returns {@code null}.
116 | * (There can be at most one such mapping.)
117 | *
118 | *
A return value of {@code null} does not necessarily
119 | * indicate that the map contains no mapping for the key; it's also
120 | * possible that the map explicitly maps the key to {@code null}.
121 | * The {@link #containsKey containsKey} operation may be used to
122 | * distinguish these two cases.
123 | *
124 | * @throws ClassCastException if the specified key cannot be compared
125 | * with the keys currently in the map
126 | * @throws NullPointerException if the specified key is null
127 | * and this map uses natural ordering, or its comparator
128 | * does not permit null keys
129 | */
130 | public V get(Object key) {
131 | Entry p = getEntry(key);
132 | return (p==null ? null : p.value);
133 | }
134 |
135 | /**
136 | * Node in the Tree.
137 | * Doubles as a means to pass key-value pairs back to
138 | * user (see Map.Entry).
139 | */
140 | static final class Entry implements Map.Entry {
141 | K key;
142 | V value;
143 | Entry left = null;
144 | Entry right = null;
145 | byte balance = 0; // Height(RightSubtree(N)) - Height(LeftSubtree(N)) i.e. right heavy=positive balance, left heavy negative
146 |
147 | /**
148 | * Make a new cell with given key, value, and parent, and with
149 | * {@code null} child links, and BLACK color.
150 | */
151 | Entry(K key, V value, Entry parent) {
152 | this.key = key;
153 | this.value = value;
154 | }
155 |
156 | /**
157 | * Returns the key.
158 | *
159 | * @return the key
160 | */
161 | public K getKey() {
162 | return key;
163 | }
164 |
165 | /**
166 | * Returns the value associated with the key.
167 | *
168 | * @return the value associated with the key
169 | */
170 | public V getValue() {
171 | return value;
172 | }
173 |
174 | /**
175 | * Replaces the value currently associated with the key with the given
176 | * value.
177 | *
178 | * @return the value associated with the key before this method was
179 | * called
180 | */
181 | public V setValue(V value) {
182 | V oldValue = this.value;
183 | this.value = value;
184 | return oldValue;
185 | }
186 |
187 | public boolean equals(Object o) {
188 | if (!(o instanceof Map.Entry))
189 | return false;
190 | Map.Entry,?> e = (Map.Entry,?>)o;
191 |
192 | return valEquals(key,e.getKey()) && valEquals(value,e.getValue());
193 | }
194 |
195 | public int hashCode() {
196 | int keyHash = (key==null ? 0 : key.hashCode());
197 | int valueHash = (value==null ? 0 : value.hashCode());
198 | return keyHash ^ valueHash;
199 | }
200 |
201 | public String toString() {
202 | return key + "=" + value;
203 | }
204 | }
205 |
206 | /**
207 | * Returns this map's entry for the given key, or {@code null} if the map
208 | * does not contain an entry for the key.
209 | *
210 | * @return this map's entry for the given key, or {@code null} if the map
211 | * does not contain an entry for the key
212 | * @throws ClassCastException if the specified key cannot be compared
213 | * with the keys currently in the map
214 | * @throws NullPointerException if the specified key is null
215 | * and this map uses natural ordering, or its comparator
216 | * does not permit null keys
217 | */
218 | final Entry getEntry(Object key) {
219 | // Offload comparator-based version for sake of performance
220 | if (comparator != null)
221 | return getEntryUsingComparator(key);
222 | if (key == null)
223 | throw new NullPointerException();
224 | @SuppressWarnings("unchecked")
225 | Comparable super K> k = (Comparable super K>) key;
226 | Entry p = root;
227 | while (p != null) {
228 | int cmp = k.compareTo(p.key);
229 | if (cmp < 0)
230 | p = p.left;
231 | else if (cmp > 0)
232 | p = p.right;
233 | else
234 | return p;
235 | }
236 | return null;
237 | }
238 |
239 | /**
240 | * Version of getEntry using comparator. Split off from getEntry
241 | * for performance. (This is not worth doing for most methods,
242 | * that are less dependent on comparator performance, but is
243 | * worthwhile here.)
244 | */
245 | final Entry getEntryUsingComparator(Object key) {
246 | @SuppressWarnings("unchecked")
247 | K k = (K) key;
248 | Comparator super K> cpr = comparator;
249 | if (cpr != null) {
250 | Entry p = root;
251 | while (p != null) {
252 | int cmp = cpr.compare(k, p.key);
253 | if (cmp < 0)
254 | p = p.left;
255 | else if (cmp > 0)
256 | p = p.right;
257 | else
258 | return p;
259 | }
260 | }
261 | return null;
262 | }
263 |
264 | /**
265 | * Associates the specified value with the specified key in this map.
266 | * If the map previously contained a mapping for the key, the old
267 | * value is replaced.
268 | *
269 | * @param key key with which the specified value is to be associated
270 | * @param value value to be associated with the specified key
271 | *
272 | * @return the previous value associated with {@code key}, or
273 | * {@code null} if there was no mapping for {@code key}.
274 | * (A {@code null} return can also indicate that the map
275 | * previously associated {@code null} with {@code key}.)
276 | * @throws ClassCastException if the specified key cannot be compared
277 | * with the keys currently in the map
278 | * @throws NullPointerException if the specified key is null
279 | * and this map uses natural ordering, or its comparator
280 | * does not permit null keys
281 | */
282 | // TODO
283 | private byte[] direction = new byte[100];
284 | @SuppressWarnings("unchecked")
285 | private Entry [] stack = new Entry[100];
286 |
287 | public V put(K key, V value) {
288 | //System.out.println("Inserting:" + key);
289 | Entry t = root;
290 | if (t == null) {
291 | compare(key, key); // type (and possibly null) check
292 |
293 | root = new Entry<>(key, value, null);
294 | size = 1;
295 | modCount++;
296 | return null;
297 | }
298 | int cmp;
299 | Entry parent;
300 | int treeDepth = 0;
301 | // split comparator and comparable paths
302 | Comparator super K> cpr = comparator;
303 | if (cpr != null) {
304 | do {
305 | parent = t;
306 | cmp = cpr.compare(key, t.key);
307 | if (cmp < 0) {
308 | t = t.left;
309 | // TODO
310 | } else if (cmp > 0) {
311 | t = t.right;
312 | }else {
313 | return t.setValue(value);
314 | }
315 | } while (t != null);
316 | } else {
317 | if (key == null)
318 | throw new NullPointerException();
319 | @SuppressWarnings("unchecked")
320 | Comparable super K> k = (Comparable super K>) key;
321 | do {
322 | parent = t;
323 | cmp = k.compareTo(t.key);
324 | if (cmp < 0) {
325 | stack[treeDepth] = parent;
326 | direction[treeDepth++] = -1;
327 | t = t.left;
328 | } else if (cmp > 0) {
329 | stack[treeDepth] = parent;
330 | direction[treeDepth++] = +1;
331 | t = t.right;
332 | } else {
333 | return t.setValue(value);
334 | }
335 | } while (t != null);
336 | }
337 |
338 | Entry e = new Entry<>(key, value, parent);
339 | if (cmp < 0) {
340 | parent.left = e;
341 | } else {
342 | parent.right = e;
343 | }
344 | fixAfterInsertion(parent, --treeDepth);
345 |
346 | size++;
347 | modCount++;
348 | return null;
349 | }
350 |
351 | private void fixAfterInsertion(Entry x, int treeDepth) {
352 | while ((x.balance += direction[treeDepth]) != 0) {
353 | if (x.balance == 2) { // right heavy by 2?
354 | if (x.right.balance == 1) {
355 | x.balance = 0;
356 | x.right.balance = 0;
357 | x = rotateLeft(x);
358 | break;
359 | } else { // x.right.balance = -1
360 | int rlBalance = x.right.left.balance;
361 | x.right.left.balance = 0;
362 | x.right.balance = 0;
363 | x.balance = 0;
364 | if (rlBalance == 1)
365 | x.balance = -1;
366 | else if (rlBalance == -1)
367 | x.right.balance = 1;
368 |
369 | x.right = rotateRight(x.right);
370 | x = rotateLeft(x);
371 | break;
372 | }
373 | } else if (x.balance == -2) {
374 | if (x.left.balance == -1) {
375 | x.balance = 0;
376 | x.left.balance = 0;
377 | x = rotateRight(x);
378 | break;
379 | } else { // x.left.balance = 1
380 | int lrBalance = x.left.right.balance;
381 | x.left.right.balance = 0;
382 | x.left.balance = 0;
383 | x.balance = 0;
384 | if (lrBalance == 1)
385 | x.left.balance = -1;
386 | else if (lrBalance == -1)
387 | x.balance = 1;
388 |
389 | x.left = rotateLeft(x.left);
390 | x = rotateRight(x);
391 | break;
392 | }
393 | }
394 | treeDepth--;
395 | if (treeDepth == -1) {
396 | return;
397 | }
398 | x = stack[treeDepth];
399 | }
400 | // set parent reference if necessary
401 | treeDepth--;
402 |
403 | if (treeDepth == -1)
404 | root = x;
405 | else if (direction[treeDepth] == 1)
406 | stack[treeDepth].right = x;
407 | else
408 | stack[treeDepth].left = x;
409 | }
410 |
411 | private Entry rotateLeft(Entry p) {
412 | Entry r = p.right;
413 | p.right = r.left;
414 | r.left = p;
415 | rotations++;
416 | return r;
417 | }
418 |
419 | private Entry rotateRight(Entry p) {
420 | Entry l = p.left;
421 | p.left = l.right;
422 | l.right = p;
423 | rotations++;
424 | return l;
425 | }
426 |
427 | public void inOrderTraversal(Entry x) {
428 | if (x == null)
429 | return;
430 | inOrderTraversal(x.left);
431 | System.out.println(x.value + ", " + x.balance);
432 | inOrderTraversal(x.right);
433 | }
434 |
435 | /**
436 | * Removes the mapping for this key from this TreeMap if present.
437 | *
438 | * @param key key for which mapping should be removed
439 | * @return the previous value associated with {@code key}, or
440 | * {@code null} if there was no mapping for {@code key}.
441 | * (A {@code null} return can also indicate that the map
442 | * previously associated {@code null} with {@code key}.)
443 | * @throws ClassCastException if the specified key cannot be compared
444 | * with the keys currently in the map
445 | * @throws NullPointerException if the specified key is null
446 | * and this map uses natural ordering, or its comparator
447 | * does not permit null keys
448 | */
449 | public V remove(Object key) {
450 | Entry p = getEntry(key);
451 | if (p == null)
452 | return null;
453 |
454 | V oldValue = p.value;
455 | deleteEntry(p);
456 | return oldValue;
457 | }
458 |
459 | private void deleteEntry(Entry p) {
460 | modCount++;
461 | size--;
462 | // TODO
463 | }
464 |
465 | /**
466 | * Removes all of the mappings from this map.
467 | * The map will be empty after this call returns.
468 | */
469 | public void clear() {
470 | modCount++;
471 | size = 0;
472 | root = null;
473 | rotations = 0;
474 | }
475 |
476 | /**
477 | * Test two values for equality. Differs from o1.equals(o2) only in
478 | * that it copes with {@code null} o1 properly.
479 | */
480 | static final boolean valEquals(Object o1, Object o2) {
481 | return (o1==null ? o2==null : o1.equals(o2));
482 | }
483 |
484 | /**
485 | * Compares two keys using the correct comparison method for this TreeMap.
486 | */
487 | @SuppressWarnings("unchecked")
488 | final int compare(Object k1, Object k2) {
489 | return comparator == null ? ((Comparable super K>) k1).compareTo((K) k2) : comparator.compare((K) k1, (K) k2);
490 | }
491 |
492 | /**
493 | * Returns the key corresponding to the specified Entry.
494 | * @throws NoSuchElementException if the Entry is null
495 | */
496 | static K key(Entry e) {
497 | if (e==null)
498 | throw new NoSuchElementException();
499 | return e.key;
500 | }
501 |
502 | /**
503 | * Returns the first Entry in the TreeMap (according to the TreeMap's
504 | * key-sort function). Returns null if the TreeMap is empty.
505 | */
506 | final Entry getFirstEntry() {
507 | Entry p = root;
508 | if (p != null)
509 | while (p.left != null)
510 | p = p.left;
511 | return p;
512 | }
513 |
514 | /**
515 | * Returns the last Entry in the TreeMap (according to the TreeMap's
516 | * key-sort function). Returns null if the TreeMap is empty.
517 | */
518 | final Entry getLastEntry() {
519 | Entry p = root;
520 | if (p != null)
521 | while (p.right != null)
522 | p = p.right;
523 | return p;
524 | }
525 |
526 | /**
527 | * Returns the successor of the specified Entry, or null if no such.
528 | */
529 | static Entry successor(Entry t) {
530 | if (t == null)
531 | return null;
532 | else if (t.right != null) {
533 | Entry p = t.right;
534 | while (p.left != null)
535 | p = p.left;
536 | return p;
537 | } else {
538 | // TODO
539 | /*
540 | Entry p = t.parent;
541 | Entry ch = t;
542 | while (p != null && ch == p.right) {
543 | ch = p;
544 | p = p.parent;
545 | }
546 | return p;
547 | */
548 | return null;
549 | }
550 | }
551 |
552 | /**
553 | * Returns the predecessor of the specified Entry, or null if no such.
554 | */
555 | static Entry predecessor(Entry t) {
556 | if (t == null)
557 | return null;
558 | else if (t.left != null) {
559 | Entry p = t.left;
560 | while (p.right != null)
561 | p = p.right;
562 | return p;
563 | } else {
564 | // TODO
565 | /*
566 | Entry p = t.parent;
567 | Entry ch = t;
568 | while (p != null && ch == p.left) {
569 | ch = p;
570 | p = p.parent;
571 | }
572 | return p;
573 | */
574 | return null;
575 | }
576 | }
577 |
578 | /**
579 | * Return SimpleImmutableEntry for entry, or null if null
580 | */
581 | static Map.Entry exportEntry(TreeMapAVLStack.Entry e) {
582 | return (e == null) ? null :
583 | new AbstractMap.SimpleImmutableEntry<>(e);
584 | }
585 |
586 | /**
587 | * Return key for entry, or null if null
588 | */
589 | static K keyOrNull(TreeMapAVLStack.Entry e) {
590 | return (e == null) ? null : e.key;
591 | }
592 |
593 | // NavigableMap API methods
594 |
595 | /**
596 | * @since 1.6
597 | */
598 | public Map.Entry firstEntry() {
599 | return exportEntry(getFirstEntry());
600 | }
601 |
602 | /**
603 | * @since 1.6
604 | */
605 | public Map.Entry lastEntry() {
606 | return exportEntry(getLastEntry());
607 | }
608 |
609 | /**
610 | * @since 1.6
611 | */
612 | public Map.Entry pollFirstEntry() {
613 | Entry p = getFirstEntry();
614 | Map.Entry result = exportEntry(p);
615 | if (p != null)
616 | deleteEntry(p);
617 | return result;
618 | }
619 |
620 | /**
621 | * @since 1.6
622 | */
623 | public Map.Entry pollLastEntry() {
624 | Entry p = getLastEntry();
625 | Map.Entry result = exportEntry(p);
626 | if (p != null)
627 | deleteEntry(p);
628 | return result;
629 | }
630 |
631 | @Override
632 | public Set> entrySet() {
633 | // TODO Auto-generated method stub
634 | return null;
635 | }
636 | }
--------------------------------------------------------------------------------
/src/main/java/bbst_showdown/AVLTreeMapRB.java:
--------------------------------------------------------------------------------
1 | package bbst_showdown;
2 |
3 | import java.util.AbstractMap;
4 | import java.util.Comparator;
5 | import java.util.Map;
6 | import java.util.NoSuchElementException;
7 | import java.util.Set;
8 |
9 |
10 | /**
11 | * A rank-balanced AVL tree implementation with only one extra bit per node -
12 | * (delta rank is one or two by definition of the rank-balanced AVL tree).
13 | *
14 | * This code is based on the paper "Rank Balanced Trees".
15 | *
16 | * At the time I wrote it I found no other similar implementations.
17 | *
18 | * TODO
19 | * I didn't code the delete method yet. If you need it email me, minimum 1 day of work needed.
20 | *
21 | * @author David McManamon
22 | *
23 | * @param the type of keys maintained by this map
24 | * @param the type of mapped values
25 | */
26 | public class AVLTreeMapRB extends AbstractMap {
27 | // every node except the root must have a delta r of 1 or 2
28 | protected static final boolean ONE = true;
29 | protected static final boolean TWO = false;
30 |
31 | protected transient Entry root = null;
32 |
33 | /**
34 | * The number of entries in the tree
35 | */
36 | protected transient int size = 0;
37 |
38 | /**
39 | * The comparator used to maintain order in this tree map, or
40 | * null if it uses the natural ordering of its keys.
41 | *
42 | * @serial
43 | */
44 | protected final Comparator super K> comparator;
45 |
46 | /**
47 | * The number of structural modifications to the tree.
48 | */
49 | protected transient int modCount = 0;
50 |
51 | protected transient int rotations = 0;
52 |
53 | /**
54 | * Constructs a new, empty tree map, using the natural ordering of its
55 | * keys. All keys inserted into the map must implement the {@link
56 | * Comparable} interface. Furthermore, all such keys must be
57 | * mutually comparable: {@code k1.compareTo(k2)} must not throw
58 | * a {@code ClassCastException} for any keys {@code k1} and
59 | * {@code k2} in the map. If the user attempts to put a key into the
60 | * map that violates this constraint (for example, the user attempts to
61 | * put a string key into a map whose keys are integers), the
62 | * {@code put(Object key, Object value)} call will throw a
63 | * {@code ClassCastException}.
64 | */
65 | public AVLTreeMapRB() {
66 | comparator = null;
67 | }
68 |
69 | /**
70 | * Constructs a new tree map containing the same mappings as the given
71 | * map, ordered according to the natural ordering of its keys.
72 | * All keys inserted into the new map must implement the {@link
73 | * Comparable} interface. Furthermore, all such keys must be
74 | * mutually comparable: {@code k1.compareTo(k2)} must not throw
75 | * a {@code ClassCastException} for any keys {@code k1} and
76 | * {@code k2} in the map. This method runs in n*log(n) time.
77 | *
78 | * @param m the map whose mappings are to be placed in this map
79 | * @throws ClassCastException if the keys in m are not {@link Comparable},
80 | * or are not mutually comparable
81 | * @throws NullPointerException if the specified map is null
82 | */
83 | public AVLTreeMapRB(Map extends K, ? extends V> m) {
84 | comparator = null;
85 | putAll(m);
86 | }
87 |
88 | public int treeHeight() {
89 | return treeHeight(root) - 1;
90 | }
91 |
92 | protected int treeHeight(Entry node) {
93 | if (node == null)
94 | return 0;
95 | return (1 + Math.max(treeHeight(node.left), treeHeight(node.right)));
96 | }
97 |
98 | public int rotations() {
99 | return rotations;
100 | }
101 |
102 | public String toString() {
103 | return "Rank balanced AVL tree of size: " + size + ", height: " + treeHeight() + ", rotations " + rotations;
104 | }
105 |
106 | /**
107 | * Returns the number of key-value mappings in this map.
108 | *
109 | * @return the number of key-value mappings in this map
110 | */
111 | public int size() {
112 | return size;
113 | }
114 |
115 | /**
116 | * Returns the value to which the specified key is mapped,
117 | * or {@code null} if this map contains no mapping for the key.
118 | *
119 | * More formally, if this map contains a mapping from a key
120 | * {@code k} to a value {@code v} such that {@code key} compares
121 | * equal to {@code k} according to the map's ordering, then this
122 | * method returns {@code v}; otherwise it returns {@code null}.
123 | * (There can be at most one such mapping.)
124 | *
125 | *
A return value of {@code null} does not necessarily
126 | * indicate that the map contains no mapping for the key; it's also
127 | * possible that the map explicitly maps the key to {@code null}.
128 | * The {@link #containsKey containsKey} operation may be used to
129 | * distinguish these two cases.
130 | *
131 | * @throws ClassCastException if the specified key cannot be compared
132 | * with the keys currently in the map
133 | * @throws NullPointerException if the specified key is null
134 | * and this map uses natural ordering, or its comparator
135 | * does not permit null keys
136 | */
137 | public V get(Object key) {
138 | Entry p = getEntry(key);
139 | return (p==null ? null : p.value);
140 | }
141 |
142 | /**
143 | * Node in the Tree.
144 | * Doubles as a means to pass key-value pairs back to
145 | * user (see Map.Entry).
146 | */
147 | static final class Entry implements Map.Entry {
148 | K key;
149 | V value;
150 | Entry left = null;
151 | Entry right = null;
152 | Entry parent = null;
153 | boolean deltaR = ONE;
154 |
155 | /**
156 | * Make a new cell with given key, value, and parent, and with
157 | * {@code null} child links, and delta r of 1
158 | */
159 | Entry(K key, V value, Entry parent) {
160 | this.key = key;
161 | this.value = value;
162 | this.parent = parent;
163 | }
164 |
165 | /**
166 | * Returns the key.
167 | *
168 | * @return the key
169 | */
170 | public K getKey() {
171 | return key;
172 | }
173 |
174 | /**
175 | * Returns the value associated with the key.
176 | *
177 | * @return the value associated with the key
178 | */
179 | public V getValue() {
180 | return value;
181 | }
182 |
183 | /**
184 | * Replaces the value currently associated with the key with the given
185 | * value.
186 | *
187 | * @return the value associated with the key before this method was
188 | * called
189 | */
190 | public V setValue(V value) {
191 | V oldValue = this.value;
192 | this.value = value;
193 | return oldValue;
194 | }
195 |
196 | public boolean equals(Object o) {
197 | if (!(o instanceof Map.Entry))
198 | return false;
199 | Map.Entry,?> e = (Map.Entry,?>)o;
200 |
201 | return valEquals(key,e.getKey()) && valEquals(value,e.getValue());
202 | }
203 |
204 | public int hashCode() {
205 | int keyHash = (key==null ? 0 : key.hashCode());
206 | int valueHash = (value==null ? 0 : value.hashCode());
207 | return keyHash ^ valueHash;
208 | }
209 |
210 | public String toString() {
211 | return key + "=" + value + "," + deltaR;
212 | }
213 | }
214 |
215 | /**
216 | * Returns this map's entry for the given key, or {@code null} if the map
217 | * does not contain an entry for the key.
218 | *
219 | * @return this map's entry for the given key, or {@code null} if the map
220 | * does not contain an entry for the key
221 | * @throws ClassCastException if the specified key cannot be compared
222 | * with the keys currently in the map
223 | * @throws NullPointerException if the specified key is null
224 | * and this map uses natural ordering, or its comparator
225 | * does not permit null keys
226 | */
227 | final Entry getEntry(Object key) {
228 | // Offload comparator-based version for sake of performance
229 | if (comparator != null)
230 | return getEntryUsingComparator(key);
231 | if (key == null)
232 | throw new NullPointerException();
233 | @SuppressWarnings("unchecked")
234 | Comparable super K> k = (Comparable super K>) key;
235 | Entry p = root;
236 | while (p != null) {
237 | int cmp = k.compareTo(p.key);
238 | if (cmp < 0)
239 | p = p.left;
240 | else if (cmp > 0)
241 | p = p.right;
242 | else
243 | return p;
244 | }
245 | return null;
246 | }
247 |
248 | /**
249 | * Version of getEntry using comparator. Split off from getEntry
250 | * for performance. (This is not worth doing for most methods,
251 | * that are less dependent on comparator performance, but is
252 | * worthwhile here.)
253 | */
254 | final Entry getEntryUsingComparator(Object key) {
255 | @SuppressWarnings("unchecked")
256 | K k = (K) key;
257 | Comparator super K> cpr = comparator;
258 | if (cpr != null) {
259 | Entry p = root;
260 | while (p != null) {
261 | int cmp = cpr.compare(k, p.key);
262 | if (cmp < 0)
263 | p = p.left;
264 | else if (cmp > 0)
265 | p = p.right;
266 | else
267 | return p;
268 | }
269 | }
270 | return null;
271 | }
272 |
273 | /**
274 | * Associates the specified value with the specified key in this map.
275 | * If the map previously contained a mapping for the key, the old
276 | * value is replaced.
277 | *
278 | * @param key key with which the specified value is to be associated
279 | * @param value value to be associated with the specified key
280 | *
281 | * @return the previous value associated with {@code key}, or
282 | * {@code null} if there was no mapping for {@code key}.
283 | * (A {@code null} return can also indicate that the map
284 | * previously associated {@code null} with {@code key}.)
285 | * @throws ClassCastException if the specified key cannot be compared
286 | * with the keys currently in the map
287 | * @throws NullPointerException if the specified key is null
288 | * and this map uses natural ordering, or its comparator
289 | * does not permit null keys
290 | */
291 | public V put(K key, V value) {
292 | Entry t = root;
293 | if (t == null) {
294 | compare(key, key); // type (and possibly null) check
295 |
296 | root = new Entry<>(key, value, null);
297 | size = 1;
298 | modCount++;
299 | return null;
300 | }
301 | int cmp;
302 | Entry parent;
303 | // split comparator and comparable paths
304 | Comparator super K> cpr = comparator;
305 | if (cpr != null) {
306 | do {
307 | parent = t;
308 | cmp = cpr.compare(key, t.key);
309 | if (cmp < 0)
310 | t = t.left;
311 | else if (cmp > 0)
312 | t = t.right;
313 | else
314 | return t.setValue(value);
315 | } while (t != null);
316 | } else {
317 | if (key == null)
318 | throw new NullPointerException();
319 | @SuppressWarnings("unchecked")
320 | Comparable super K> k = (Comparable super K>) key;
321 | do {
322 | parent = t;
323 | cmp = k.compareTo(t.key);
324 | if (cmp < 0)
325 | t = t.left;
326 | else if (cmp > 0)
327 | t = t.right;
328 | else
329 | return t.setValue(value);
330 | } while (t != null);
331 | }
332 |
333 | Entry e = new Entry<>(key, value, parent);
334 | Entry sibling;
335 | if (cmp < 0) {
336 | parent.left = e;
337 | sibling = parent.right;
338 | } else {
339 | parent.right = e;
340 | sibling = parent.left;
341 | }
342 |
343 | if (sibling == null)
344 | fixAfterInsertion(parent);
345 |
346 | size++;
347 | modCount++;
348 | return null;
349 | }
350 |
351 | /**
352 | If the path of incremented ranks reaches the root of the tree, then the rebalancing procedure stops.
353 | If the path of incremented ranks reaches a node whose parent's rank previously differed by two, the rebalancing procedure stops.
354 | If the procedure increases the rank of a node x, so that it becomes equal to the rank of the parent y of x,
355 | but the other child of y has a rank that is smaller by two (so that the rank of y cannot be increased)
356 | then again the rebalancing procedure stops after performing rotations necessary.
357 | */
358 | private void fixAfterInsertion(Entry x) {
359 | while (x.deltaR != TWO && x.parent != null) {
360 | Entry p = x.parent;
361 | if (p.left == x) { // node was added on left so check if left side is unbalanced
362 | Entry sibling = p.right;
363 | if (sibling == null || sibling.deltaR == TWO) { // need to rebalance
364 | if (sibling != null)
365 | sibling.deltaR = ONE;
366 |
367 | if (x.right != null) {
368 | if(x.right.deltaR == ONE) {
369 | if (x.left != null) x.left.deltaR = ONE;
370 | rotateLeft(x);
371 | } else
372 | x.right.deltaR = ONE;
373 | }
374 |
375 | if (p.deltaR == TWO) { // maintain delta 2 at parent
376 | p.deltaR = ONE;
377 | p.left.deltaR = TWO;
378 | }
379 | rotateRight(p);
380 | return;
381 | } else if (sibling.deltaR == ONE) {
382 | sibling.deltaR = TWO;
383 | }
384 | } else { // checking right side heavy
385 | Entry sibling = p.left;
386 | if (sibling == null || sibling.deltaR == TWO) { // need to rebalance
387 | if (sibling != null)
388 | sibling.deltaR = ONE;
389 |
390 | if (x.left != null) {
391 | if (x.left.deltaR == ONE) {
392 | if (x.right != null) x.right.deltaR = ONE;
393 | rotateRight(x);
394 | } else
395 | x.left.deltaR = ONE;
396 | }
397 |
398 | if (p.deltaR == TWO) { // maintain delta 2 at parent
399 | p.deltaR = ONE;
400 | p.right.deltaR = TWO;
401 | }
402 | rotateLeft(p);
403 | return;
404 | } else if (sibling.deltaR == ONE) {
405 | sibling.deltaR = TWO;
406 | }
407 | }
408 |
409 | x = x.parent;
410 | }
411 | if (x.deltaR == TWO)
412 | x.deltaR=ONE;
413 | }
414 |
415 |
416 | /** From CLR */
417 | private void rotateLeft(Entry p) {
418 | Entry r = p.right;
419 | p.right = r.left;
420 | if (r.left != null)
421 | r.left.parent = p;
422 | r.parent = p.parent;
423 | if (p.parent == null)
424 | root = r;
425 | else if (p.parent.left == p)
426 | p.parent.left = r;
427 | else
428 | p.parent.right = r;
429 | r.left = p;
430 | p.parent = r;
431 | rotations++;
432 | }
433 |
434 | /** From CLR */
435 | private void rotateRight(Entry p) {
436 | Entry l = p.left;
437 | p.left = l.right;
438 | if (l.right != null)
439 | l.right.parent = p;
440 | l.parent = p.parent;
441 | if (p.parent == null)
442 | root = l;
443 | else if (p.parent.right == p)
444 | p.parent.right = l;
445 | else
446 | p.parent.left = l;
447 | l.right = p;
448 | p.parent = l;
449 | rotations++;
450 | }
451 |
452 | /**
453 | * Removes the mapping for this key from this TreeMap if present.
454 | *
455 | * @param key key for which mapping should be removed
456 | * @return the previous value associated with {@code key}, or
457 | * {@code null} if there was no mapping for {@code key}.
458 | * (A {@code null} return can also indicate that the map
459 | * previously associated {@code null} with {@code key}.)
460 | * @throws ClassCastException if the specified key cannot be compared
461 | * with the keys currently in the map
462 | * @throws NullPointerException if the specified key is null
463 | * and this map uses natural ordering, or its comparator
464 | * does not permit null keys
465 | */
466 | public V remove(Object key) {
467 | Entry p = getEntry(key);
468 | if (p == null)
469 | return null;
470 |
471 | V oldValue = p.value;
472 | deleteEntry(p);
473 | return oldValue;
474 | }
475 |
476 | /**
477 | * Delete node p, and then rebalance the tree.
478 | */
479 | private void deleteEntry(Entry p) {
480 | modCount++;
481 | size--;
482 |
483 | // If strictly internal, copy successor's element to p and then make p
484 | // point to successor.
485 | if (p.left != null && p.right != null) {
486 | Entry s = successor(p);
487 | p.key = s.key;
488 | p.value = s.value;
489 | p = s;
490 | } // p has 2 children
491 |
492 | // Start fixup at replacement node, if it exists.
493 | Entry replacement = (p.left != null ? p.left : p.right);
494 |
495 | if (replacement != null) {
496 | // Link replacement to parent
497 | replacement.parent = p.parent;
498 | Entry mirror = null;
499 | if (p.parent == null) {
500 | root = replacement;
501 | return;
502 | } else if (p == p.parent.left) {
503 | p.parent.left = replacement;
504 | mirror = p.parent.right;
505 | } else {
506 | p.parent.right = replacement;
507 | mirror = p.parent.left;
508 | }
509 |
510 | // Null out links so they are OK to use by fixAfterDeletion.
511 | p.left = p.right = p.parent = null;
512 | //TODO
513 | fixAfterDeletion(replacement.parent, mirror);
514 | } else if (p.parent == null) { // return if we are the only node.
515 | root = null;
516 | } else { // No children. Use self as phantom replacement and unlink.
517 | // TODO check if null check necessary?
518 | Entry fixPoint = p.parent;
519 | @SuppressWarnings("unused")
520 | Entry sibling = null;
521 |
522 | if (p == p.parent.left) {
523 | p.parent.left = null;
524 | sibling = fixPoint.right;
525 | } else if (p == p.parent.right) {
526 | p.parent.right = null;
527 | sibling = fixPoint.left;
528 | }
529 | p.parent = null;
530 |
531 | // TODO
532 | // if (mirror == null || (fixPoint.rank - p.rank >= 2) || (fixPoint.rank - mirror.rank) != 1 ) {
533 | fixAfterDeletion(fixPoint, null);
534 | // }
535 | }
536 | }
537 |
538 | private void fixAfterDeletion(Entry p, Entry mirror) {
539 | throw new RuntimeException();
540 | }
541 |
542 | /**
543 | * Removes all of the mappings from this map.
544 | * The map will be empty after this call returns.
545 | */
546 | public void clear() {
547 | modCount++;
548 | size = 0;
549 | root = null;
550 | rotations = 0;
551 | }
552 |
553 | /**
554 | * Test two values for equality. Differs from o1.equals(o2) only in
555 | * that it copes with {@code null} o1 properly.
556 | */
557 | static final boolean valEquals(Object o1, Object o2) {
558 | return (o1==null ? o2==null : o1.equals(o2));
559 | }
560 |
561 | /**
562 | * Compares two keys using the correct comparison method for this TreeMap.
563 | */
564 | @SuppressWarnings("unchecked")
565 | final int compare(Object k1, Object k2) {
566 | return comparator == null ? ((Comparable super K>) k1).compareTo((K) k2) : comparator.compare((K) k1, (K) k2);
567 | }
568 |
569 | /**
570 | * Returns the key corresponding to the specified Entry.
571 | *
572 | * @throws NoSuchElementException
573 | * if the Entry is null
574 | */
575 | static K key(Entry e) {
576 | if (e==null)
577 | throw new NoSuchElementException();
578 | return e.key;
579 | }
580 |
581 | /**
582 | * Returns the first Entry in the TreeMap (according to the TreeMap's
583 | * key-sort function). Returns null if the TreeMap is empty.
584 | */
585 | final Entry getFirstEntry() {
586 | Entry p = root;
587 | if (p != null)
588 | while (p.left != null)
589 | p = p.left;
590 | return p;
591 | }
592 |
593 | /**
594 | * Returns the last Entry in the TreeMap (according to the TreeMap's
595 | * key-sort function). Returns null if the TreeMap is empty.
596 | */
597 | final Entry getLastEntry() {
598 | Entry p = root;
599 | if (p != null)
600 | while (p.right != null)
601 | p = p.right;
602 | return p;
603 | }
604 |
605 | /**
606 | * Returns the successor of the specified Entry, or null if no such.
607 | */
608 | static Entry successor(Entry t) {
609 | if (t == null)
610 | return null;
611 | else if (t.right != null) {
612 | Entry p = t.right;
613 | while (p.left != null)
614 | p = p.left;
615 | return p;
616 | } else {
617 | Entry p = t.parent;
618 | Entry ch = t;
619 | while (p != null && ch == p.right) {
620 | ch = p;
621 | p = p.parent;
622 | }
623 | return p;
624 | }
625 | }
626 |
627 | /**
628 | * Returns the predecessor of the specified Entry, or null if no such.
629 | */
630 | static Entry predecessor(Entry t) {
631 | if (t == null)
632 | return null;
633 | else if (t.left != null) {
634 | Entry p = t.left;
635 | while (p.right != null)
636 | p = p.right;
637 | return p;
638 | } else {
639 | Entry p = t.parent;
640 | Entry ch = t;
641 | while (p != null && ch == p.left) {
642 | ch = p;
643 | p = p.parent;
644 | }
645 | return p;
646 | }
647 | }
648 |
649 | @Override
650 | public Set> entrySet() {
651 | // TODO Auto-generated method stub
652 | return null;
653 | }
654 |
655 | public void inOrderTraversal(Entry x) {
656 | if (x == null)
657 | return;
658 | inOrderTraversal(x.left);
659 | System.out.println(x.value + ", " + x.deltaR);
660 | inOrderTraversal(x.right);
661 | }
662 |
663 | public boolean identicalTrees(Entry a, AVLTreeMap.Entry b) {
664 | /* 1. both empty */
665 | if (a == null && b == null)
666 | return true;
667 |
668 | /* 2. both non-empty -> compare them */
669 | if (a != null && b != null)
670 | return (a.value == b.value && identicalTrees(a.left, b.left) && identicalTrees(a.right, b.right));
671 |
672 | /* 3. one empty, one not -> false */
673 | return false;
674 | }
675 | }
--------------------------------------------------------------------------------
/src/main/java/bbst_showdown/WAVLTreeMap.java:
--------------------------------------------------------------------------------
1 | package bbst_showdown;
2 |
3 | import java.util.AbstractMap;
4 | import java.util.AbstractSet;
5 | import java.util.Comparator;
6 | import java.util.ConcurrentModificationException;
7 | import java.util.Iterator;
8 | import java.util.Map;
9 | import java.util.NoSuchElementException;
10 | import java.util.Set;
11 | import java.util.Spliterator;
12 |
13 | /**
14 | * The WAVL tree combines elements of AVL & Red-black trees.
15 | *
16 | * The WAVL tree deletion is described in the 2015 paper "Rank Balanced Trees"
17 | * The related RAVL tree is described in the 2016 paper "Deletion Without Rebalancing in Binary Search Trees"
18 | * both are available at:
19 | * http://sidsen.azurewebsites.net//
20 | *
21 | * @author David McManamon
22 | *
23 | * @param the type of keys maintained by this map
24 | * @param the type of mapped values
25 | */
26 | public class WAVLTreeMap extends AbstractMap {
27 |
28 | protected transient Entry root = null;
29 |
30 | /**
31 | * The number of entries in the tree
32 | */
33 | protected transient int size = 0;
34 |
35 | /**
36 | * The comparator used to maintain order in this tree map, or
37 | * null if it uses the natural ordering of its keys.
38 | *
39 | * @serial
40 | */
41 | protected final Comparator super K> comparator;
42 |
43 | /**
44 | * The number of structural modifications to the tree.
45 | */
46 | protected transient int modCount = 0;
47 |
48 | protected transient int rotations = 0;
49 |
50 | protected boolean deleteWAVL = false;
51 |
52 |
53 | public WAVLTreeMap() {
54 | this.comparator = null;
55 | }
56 | /**
57 | * Constructs a new, empty tree map, using the natural ordering of its
58 | * keys. All keys inserted into the map must implement the {@link
59 | * Comparable} interface. Furthermore, all such keys must be
60 | * mutually comparable: {@code k1.compareTo(k2)} must not throw
61 | * a {@code ClassCastException} for any keys {@code k1} and
62 | * {@code k2} in the map. If the user attempts to put a key into the
63 | * map that violates this constraint (for example, the user attempts to
64 | * put a string key into a map whose keys are integers), the
65 | * {@code put(Object key, Object value)} call will throw a
66 | * {@code ClassCastException}.
67 | */
68 | public WAVLTreeMap(boolean deleteWAVL) {
69 | this.deleteWAVL = deleteWAVL;
70 | this.comparator = null;
71 | }
72 |
73 | /**
74 | * Constructs a new tree map containing the same mappings as the given
75 | * map, ordered according to the natural ordering of its keys.
76 | * All keys inserted into the new map must implement the {@link
77 | * Comparable} interface. Furthermore, all such keys must be
78 | * mutually comparable: {@code k1.compareTo(k2)} must not throw
79 | * a {@code ClassCastException} for any keys {@code k1} and
80 | * {@code k2} in the map. This method runs in n*log(n) time.
81 | *
82 | * @param m the map whose mappings are to be placed in this map
83 | * @throws ClassCastException if the keys in m are not {@link Comparable},
84 | * or are not mutually comparable
85 | * @throws NullPointerException if the specified map is null
86 | */
87 | public WAVLTreeMap(Map extends K, ? extends V> m) {
88 | comparator = null;
89 | putAll(m);
90 | }
91 |
92 | public int treeHeight() {
93 | return treeHeight(root) - 1;
94 | }
95 |
96 | protected int treeHeight(Entry node) {
97 | if (node == null)
98 | return 0;
99 | return (1 + Math.max(treeHeight(node.left), treeHeight(node.right)));
100 | }
101 |
102 | public int rotations() {
103 | return rotations;
104 | }
105 |
106 | public String toString() {
107 | return "WAVL tree of size: " + size + ", height: " + treeHeight() + ", rotations " + rotations + " WAVL deletes: " + deleteWAVL + " root:" + root;
108 | }
109 |
110 | /**
111 | * Returns the number of key-value mappings in this map.
112 | *
113 | * @return the number of key-value mappings in this map
114 | */
115 | public int size() {
116 | return size;
117 | }
118 |
119 | /**
120 | * Returns the value to which the specified key is mapped,
121 | * or {@code null} if this map contains no mapping for the key.
122 | *
123 | * More formally, if this map contains a mapping from a key
124 | * {@code k} to a value {@code v} such that {@code key} compares
125 | * equal to {@code k} according to the map's ordering, then this
126 | * method returns {@code v}; otherwise it returns {@code null}.
127 | * (There can be at most one such mapping.)
128 | *
129 | *
A return value of {@code null} does not necessarily
130 | * indicate that the map contains no mapping for the key; it's also
131 | * possible that the map explicitly maps the key to {@code null}.
132 | * The {@link #containsKey containsKey} operation may be used to
133 | * distinguish these two cases.
134 | *
135 | * @throws ClassCastException if the specified key cannot be compared
136 | * with the keys currently in the map
137 | * @throws NullPointerException if the specified key is null
138 | * and this map uses natural ordering, or its comparator
139 | * does not permit null keys
140 | */
141 | public V get(Object key) {
142 | Entry p = getEntry(key);
143 | return (p==null ? null : p.value);
144 | }
145 |
146 | /**
147 | * Node in the Tree.
148 | * Doubles as a means to pass key-value pairs back to
149 | * user (see Map.Entry).
150 | */
151 | static final class Entry implements Map.Entry {
152 | K key;
153 | V value;
154 | Entry left = null;
155 | Entry right = null;
156 | Entry parent = null;
157 | byte rank = 0;
158 |
159 | /**
160 | * Make a new cell with given key, value, and parent, and with
161 | * {@code null} child links, and BLACK color.
162 | */
163 | Entry(K key, V value, Entry parent) {
164 | this.key = key;
165 | this.value = value;
166 | this.parent = parent;
167 | }
168 |
169 | Entry() {
170 | rank = -1;
171 | }
172 |
173 | /**
174 | * Returns the key.
175 | *
176 | * @return the key
177 | */
178 | public K getKey() {
179 | return key;
180 | }
181 |
182 | /**
183 | * Returns the value associated with the key.
184 | *
185 | * @return the value associated with the key
186 | */
187 | public V getValue() {
188 | return value;
189 | }
190 |
191 | /**
192 | * Replaces the value currently associated with the key with the given
193 | * value.
194 | *
195 | * @return the value associated with the key before this method was
196 | * called
197 | */
198 | public V setValue(V value) {
199 | V oldValue = this.value;
200 | this.value = value;
201 | return oldValue;
202 | }
203 |
204 | public boolean equals(Object o) {
205 | if (!(o instanceof Map.Entry))
206 | return false;
207 | Map.Entry,?> e = (Map.Entry,?>)o;
208 |
209 | return valEquals(key,e.getKey()) && valEquals(value,e.getValue());
210 | }
211 |
212 | public int hashCode() {
213 | int keyHash = (key==null ? 0 : key.hashCode());
214 | int valueHash = (value==null ? 0 : value.hashCode());
215 | return keyHash ^ valueHash;
216 | }
217 |
218 | public String toString() {
219 | return key + "=" + value + "," + rank;
220 | }
221 | }
222 |
223 | /**
224 | * Returns this map's entry for the given key, or {@code null} if the map
225 | * does not contain an entry for the key.
226 | *
227 | * @return this map's entry for the given key, or {@code null} if the map
228 | * does not contain an entry for the key
229 | * @throws ClassCastException if the specified key cannot be compared
230 | * with the keys currently in the map
231 | * @throws NullPointerException if the specified key is null
232 | * and this map uses natural ordering, or its comparator
233 | * does not permit null keys
234 | */
235 | final Entry getEntry(Object key) {
236 | // Offload comparator-based version for sake of performance
237 | if (comparator != null)
238 | return getEntryUsingComparator(key);
239 | if (key == null)
240 | throw new NullPointerException();
241 | @SuppressWarnings("unchecked")
242 | Comparable super K> k = (Comparable super K>) key;
243 | Entry p = root;
244 | while (p != null) {
245 | int cmp = k.compareTo(p.key);
246 | if (cmp < 0)
247 | p = p.left;
248 | else if (cmp > 0)
249 | p = p.right;
250 | else
251 | return p;
252 | }
253 | return null;
254 | }
255 |
256 | /**
257 | * Version of getEntry using comparator. Split off from getEntry
258 | * for performance. (This is not worth doing for most methods,
259 | * that are less dependent on comparator performance, but is
260 | * worthwhile here.)
261 | */
262 | final Entry getEntryUsingComparator(Object key) {
263 | @SuppressWarnings("unchecked")
264 | K k = (K) key;
265 | Comparator super K> cpr = comparator;
266 | if (cpr != null) {
267 | Entry p = root;
268 | while (p != null) {
269 | int cmp = cpr.compare(k, p.key);
270 | if (cmp < 0)
271 | p = p.left;
272 | else if (cmp > 0)
273 | p = p.right;
274 | else
275 | return p;
276 | }
277 | }
278 | return null;
279 | }
280 |
281 | /**
282 | * Associates the specified value with the specified key in this map.
283 | * If the map previously contained a mapping for the key, the old
284 | * value is replaced.
285 | *
286 | * @param key key with which the specified value is to be associated
287 | * @param value value to be associated with the specified key
288 | *
289 | * @return the previous value associated with {@code key}, or
290 | * {@code null} if there was no mapping for {@code key}.
291 | * (A {@code null} return can also indicate that the map
292 | * previously associated {@code null} with {@code key}.)
293 | * @throws ClassCastException if the specified key cannot be compared
294 | * with the keys currently in the map
295 | * @throws NullPointerException if the specified key is null
296 | * and this map uses natural ordering, or its comparator
297 | * does not permit null keys
298 | */
299 | public V put(K key, V value) {
300 | Entry t = root;
301 | if (t == null) {
302 | compare(key, key); // type (and possibly null) check
303 |
304 | root = new Entry<>(key, value, null);
305 | size = 1;
306 | modCount++;
307 | return null;
308 | }
309 | int cmp;
310 | Entry parent;
311 | // split comparator and comparable paths
312 | Comparator super K> cpr = comparator;
313 | if (cpr != null) {
314 | do {
315 | parent = t;
316 | cmp = cpr.compare(key, t.key);
317 | if (cmp < 0)
318 | t = t.left;
319 | else if (cmp > 0)
320 | t = t.right;
321 | else
322 | return t.setValue(value);
323 | } while (t != null);
324 | } else {
325 | if (key == null)
326 | throw new NullPointerException();
327 | @SuppressWarnings("unchecked")
328 | Comparable super K> k = (Comparable super K>) key;
329 | do {
330 | parent = t;
331 | cmp = k.compareTo(t.key);
332 | if (cmp < 0)
333 | t = t.left;
334 | else if (cmp > 0)
335 | t = t.right;
336 | else
337 | return t.setValue(value);
338 | } while (t != null);
339 | }
340 |
341 | Entry e = new Entry<>(key, value, parent);
342 | if (cmp < 0) {
343 | parent.left = e;
344 | } else {
345 | parent.right = e;
346 | }
347 |
348 | if (parent.rank == 0) {
349 | parent.rank++;
350 | fixAfterInsert(parent);
351 | }
352 |
353 | size++;
354 | modCount++;
355 | return null;
356 | }
357 |
358 | public void inOrderTraversal(Entry x) {
359 | if (x == null)
360 | return;
361 | inOrderTraversal(x.left);
362 | System.out.println(x.value + ", " + x.rank);
363 | inOrderTraversal(x.right);
364 | }
365 |
366 | /**
367 | - If the path of incremented ranks reaches the root of the tree stop.
368 | - If the path of incremented ranks reaches a node whose parent's rank previously differed by two and after incrementing now differ by one stop.
369 | - If the procedure increases the rank of a node x, so that it becomes equal to the rank of the parent y of x,
370 | but the other child of y has a rank that is smaller by two (so that the rank of y cannot be increased)
371 | then again the rebalancing procedure stops after performing rotations necessary.
372 | In other words:
373 | After insertion rank difference is 1,2 or 3 -
374 | check these three cases stopping after any rotations, reaching the root or when rank difference was 2 before the insertion.
375 | */
376 | private void fixAfterInsert(Entry x) {
377 | for (Entry parent = x.parent;
378 | parent != null && x.rank + 1 != parent.rank; x.rank++) {
379 | if (parent.left == x) { // new node was added on the left
380 | if (needToRotateRight(parent)) {
381 | if (x.left == null || x.rank >= x.left.rank + 2) {
382 | x.rank--;
383 | x.right.rank++;
384 | rotateLeft(x);
385 | }
386 | parent.rank--;
387 | rotateRight(parent);
388 | break;
389 | }
390 | } else {
391 | if (needToRotateLeft(parent)) {
392 | if (x.right == null || x.rank >= x.right.rank + 2) {
393 | x.rank--;
394 | x.left.rank++;
395 | rotateRight(x);
396 | }
397 | parent.rank--;
398 | rotateLeft(parent);
399 | break;
400 | }
401 | }
402 | x = parent;
403 | parent = x.parent;
404 | }
405 | }
406 |
407 | // check if sibling node has a rank difference of 2
408 | private boolean needToRotateLeft(Entry p) {
409 | if (p.left == null) { // rank of sibling is -1
410 | if (p.rank == 1)
411 | return true;
412 | return false;
413 | } else if (p.rank >= p.left.rank + 2)
414 | return true;
415 | return false;
416 | }
417 |
418 | // check if sibling node has a rank difference of 2 or greater (RAVL)
419 | private boolean needToRotateRight(Entry p) {
420 | if (p.right == null) { // rank of sibling is -1
421 | if (p.rank == 1)
422 | return true;
423 | return false;
424 | } else if (p.rank >= p.right.rank + 2)
425 | return true;
426 | return false;
427 | }
428 |
429 | /** From CLR */
430 | private void rotateLeft(Entry p) {
431 | Entry r = p.right;
432 | p.right = r.left;
433 | if (r.left != null)
434 | r.left.parent = p;
435 | r.parent = p.parent;
436 | if (p.parent == null)
437 | root = r;
438 | else if (p.parent.left == p)
439 | p.parent.left = r;
440 | else
441 | p.parent.right = r;
442 | r.left = p;
443 | p.parent = r;
444 | rotations++;
445 | }
446 |
447 | /** From CLR */
448 | private void rotateRight(Entry p) {
449 | Entry l = p.left;
450 | p.left = l.right;
451 | if (l.right != null)
452 | l.right.parent = p;
453 | l.parent = p.parent;
454 | if (p.parent == null)
455 | root = l;
456 | else if (p.parent.right == p)
457 | p.parent.right = l;
458 | else
459 | p.parent.left = l;
460 | l.right = p;
461 | p.parent = l;
462 | rotations++;
463 | }
464 |
465 | /**
466 | * Removes the mapping for this key from this TreeMap if present.
467 | *
468 | * @param key key for which mapping should be removed
469 | * @return the previous value associated with {@code key}, or
470 | * {@code null} if there was no mapping for {@code key}.
471 | * (A {@code null} return can also indicate that the map
472 | * previously associated {@code null} with {@code key}.)
473 | * @throws ClassCastException if the specified key cannot be compared
474 | * with the keys currently in the map
475 | * @throws NullPointerException if the specified key is null
476 | * and this map uses natural ordering, or its comparator
477 | * does not permit null keys
478 | */
479 | public V remove(Object key) {
480 | Entry p = getEntry(key);
481 | if (p == null)
482 | return null;
483 |
484 | V oldValue = p.value;
485 | deleteEntry(p);
486 | return oldValue;
487 | }
488 |
489 | /**
490 | * Delete node p, and then rebalance the tree.
491 | */
492 | private void deleteEntry(Entry p) {
493 | modCount++;
494 | size--;
495 |
496 | // If strictly internal, copy successor's element to p and then make p
497 | // point to successor.
498 | if (p.left != null && p.right != null) {
499 | Entry s = predecessor(p);
500 | p.key = s.key;
501 | p.value = s.value;
502 | p = s;
503 | } // p has 2 children
504 |
505 | Entry replacement = (p.left != null ? p.left : p.right);
506 | if (replacement != null) {
507 | // Link replacement to parent
508 | replacement.parent = p.parent;
509 | Entry sibling = null;
510 | if (p.parent == null) {
511 | root = replacement;
512 | return;
513 | } else if (p == p.parent.left) {
514 | p.parent.left = replacement;
515 | sibling = p.parent.right;
516 | } else {
517 | p.parent.right = replacement;
518 | sibling = p.parent.left;
519 | }
520 |
521 | // Null out links so they are OK to use by fixAfterDeletion.
522 | p.left = p.right = p.parent = null;
523 | if (deleteWAVL)
524 | fixAfterDeleteWAVL(replacement.parent, sibling, replacement);
525 | else
526 | fixAfterDeleteAVL(replacement.parent, sibling, replacement);
527 | } else if (p.parent == null) { // return if we are the only node.
528 | root = null;
529 | } else { // No children. Use self as phantom replacement and unlink.
530 | Entry fixPoint = p.parent;
531 | Entry sibling = null;
532 |
533 | if (p == p.parent.left) {
534 | p.parent.left = null;
535 | sibling = fixPoint.right;
536 | } else if (p == p.parent.right) {
537 | p.parent.right = null;
538 | sibling = fixPoint.left;
539 | }
540 | p.parent = null;
541 | p.rank--;
542 | if (deleteWAVL)
543 | fixAfterDeleteWAVL(fixPoint, sibling, p);
544 | else
545 | fixAfterDeleteAVL(fixPoint, sibling, p);
546 | }
547 | }
548 |
549 | private byte rank(final Entry node) {
550 | return (node == null) ? -1 : node.rank;
551 | }
552 |
553 | private boolean nodeIsTwoTwo(Entry node) {
554 | if (node == null || node.rank == 0)
555 | return false;
556 | if (node.rank == 1) {
557 | if (node.left == null && node.right == null)
558 | return true;
559 | else
560 | return false;
561 | } else
562 | return (node.left.rank == node.right.rank && node.left.rank + 2 == node.rank);
563 | }
564 |
565 | private void fixAfterDeleteWAVL(Entry parent, Entry sibling, Entry node) {
566 | int deltaRank = parent.rank - node.rank;
567 | while (deltaRank == 3 || parent.rank == 1 && nodeIsTwoTwo(parent)) {
568 | int deltaRankSibling = (sibling == null) ? parent.rank + 1 : parent.rank - sibling.rank;
569 | if (deltaRankSibling == 2) {
570 | parent.rank--; // demote and continue loop
571 | } else {
572 | int deltaRankSiblingL = sibling.rank - rank(sibling.left);
573 | int deltaRankSiblingR = sibling.rank - rank(sibling.right);
574 |
575 | if (deltaRankSiblingL == 2 && deltaRankSiblingR == 2) {
576 | // "double demote" in the orig. paper since both parent & sibling demote
577 | parent.rank--;
578 | sibling.rank--;
579 | } else if (parent.right == sibling) { // delete was on the left
580 | if (deltaRankSiblingR == 1) { // single rotation
581 | sibling.rank++;
582 | parent.rank--;
583 | if (sibling.left == null)
584 | parent.rank--; // demote parent again
585 | rotateLeft(parent);
586 | } else { // double rotation
587 | parent.rank -= 2;
588 | sibling.rank--;
589 | sibling.left.rank += 2;
590 | rotateRight(sibling);
591 | rotateLeft(parent);
592 | }
593 | break;
594 | } else { // delete was on the right
595 | if (deltaRankSiblingL == 1) { // single rotation
596 | sibling.rank++;
597 | parent.rank--;
598 | if (sibling.right == null)
599 | parent.rank--; // demote parent again
600 | rotateRight(parent);
601 | } else { // double rotation
602 | parent.rank -= 2;
603 | sibling.rank--;
604 | sibling.right.rank += 2;
605 | rotateLeft(sibling);
606 | rotateRight(parent);
607 | }
608 | break;
609 | }
610 | }
611 |
612 | if (parent.parent == null)
613 | return;
614 | node = parent;
615 | parent = parent.parent;
616 | sibling = (parent.left == node) ? parent.right : parent.left;
617 | deltaRank = parent.rank - node.rank;
618 | }
619 | }
620 |
621 | /*
622 | * delete re-tracing via balance factor
623 | */
624 | private void fixAfterDeleteAVL(Entry parent, Entry sibling, Entry node) {
625 | int balance;
626 | if (sibling == null) // remove sibling null check inside loop by testing once here
627 | balance = -1 - node.rank;
628 | else
629 | balance = sibling.rank - node.rank;
630 |
631 | while (balance != 1) { // balance == 1 means prior to delete parent was balanced, break;
632 | if (balance == 0) {// side of delete was taller, decrement and continue
633 | parent.rank--;
634 | } else if (parent.left == sibling) {
635 | parent.rank -= 2;
636 | int siblingBalance = rank(sibling.right) - rank(sibling.left);
637 | if (siblingBalance == 0) { // parent height unchanged after rotate so break
638 | sibling.rank++;
639 | parent.rank++;
640 | rotateRight(parent);
641 | break;
642 | } else if (siblingBalance > 0) {
643 | sibling.right.rank++;
644 | sibling.rank--;
645 | rotateLeft(sibling);
646 | }
647 | rotateRight(parent);
648 | parent = parent.parent;
649 | } else { // delete on left
650 | parent.rank -= 2;
651 | int siblingBalance = rank(sibling.right) - rank(sibling.left);
652 | if (siblingBalance == 0) { // parent height unchanged after rotate so break
653 | sibling.rank++;
654 | parent.rank++;
655 | rotateLeft(parent);
656 | break;
657 | } else if (siblingBalance < 0) {
658 | sibling.left.rank++;
659 | sibling.rank--;
660 | rotateRight(sibling);
661 | }
662 | rotateLeft(parent);
663 | parent = parent.parent;
664 | }
665 |
666 | if (parent.parent == null)
667 | return;
668 | node = parent;
669 | parent = parent.parent;
670 | sibling = (parent.left == node) ? parent.right : parent.left;
671 | balance = sibling.rank - node.rank;
672 | }
673 | }
674 |
675 | /**
676 | * Removes all of the mappings from this map.
677 | * The map will be empty after this call returns.
678 | */
679 | public void clear() {
680 | modCount++;
681 | size = 0;
682 | root = null;
683 | rotations = 0;
684 | }
685 |
686 | /**
687 | * Test two values for equality. Differs from o1.equals(o2) only in
688 | * that it copes with {@code null} o1 properly.
689 | */
690 | static final boolean valEquals(Object o1, Object o2) {
691 | return (o1==null ? o2==null : o1.equals(o2));
692 | }
693 |
694 | /**
695 | * Compares two keys using the correct comparison method for this TreeMap.
696 | */
697 | @SuppressWarnings("unchecked")
698 | final int compare(Object k1, Object k2) {
699 | return comparator == null ? ((Comparable super K>) k1).compareTo((K) k2) : comparator.compare((K) k1, (K) k2);
700 | }
701 |
702 | /**
703 | * Returns the key corresponding to the specified Entry.
704 | *
705 | * @throws NoSuchElementException
706 | * if the Entry is null
707 | */
708 | static K key(Entry e) {
709 | if (e==null)
710 | throw new NoSuchElementException();
711 | return e.key;
712 | }
713 |
714 | /**
715 | * Returns the first Entry in the TreeMap (according to the TreeMap's
716 | * key-sort function). Returns null if the TreeMap is empty.
717 | */
718 | final Entry getFirstEntry() {
719 | Entry p = root;
720 | if (p != null)
721 | while (p.left != null)
722 | p = p.left;
723 | return p;
724 | }
725 |
726 | /**
727 | * Returns the last Entry in the TreeMap (according to the TreeMap's
728 | * key-sort function). Returns null if the TreeMap is empty.
729 | */
730 | final Entry getLastEntry() {
731 | Entry p = root;
732 | if (p != null)
733 | while (p.right != null)
734 | p = p.right;
735 | return p;
736 | }
737 |
738 | /**
739 | * Returns the successor of the specified Entry, or null if no such.
740 | */
741 | static Entry successor(Entry t) {
742 | if (t == null)
743 | return null;
744 | else if (t.right != null) {
745 | Entry p = t.right;
746 | while (p.left != null)
747 | p = p.left;
748 | return p;
749 | } else {
750 | Entry p = t.parent;
751 | Entry ch = t;
752 | while (p != null && ch == p.right) {
753 | ch = p;
754 | p = p.parent;
755 | }
756 | return p;
757 | }
758 | }
759 |
760 | /**
761 | * Returns the predecessor of the specified Entry, or null if no such.
762 | */
763 | static Entry predecessor(Entry t) {
764 | if (t == null)
765 | return null;
766 | else if (t.left != null) {
767 | Entry p = t.left;
768 | while (p.right != null)
769 | p = p.right;
770 | return p;
771 | } else {
772 | Entry p = t.parent;
773 | Entry ch = t;
774 | while (p != null && ch == p.left) {
775 | ch = p;
776 | p = p.parent;
777 | }
778 | return p;
779 | }
780 | }
781 |
782 | /**
783 | * Returns a {@link Set} view of the mappings contained in this map.
784 | *
785 | *
786 | * The set's iterator returns the entries in ascending key order. The sets's
787 | * spliterator is late-binding,
788 | * fail-fast, and additionally reports {@link Spliterator#SORTED} and
789 | * {@link Spliterator#ORDERED} with an encounter order that is ascending key
790 | * order.
791 | *
792 | *
793 | * The set is backed by the map, so changes to the map are reflected in the set,
794 | * and vice-versa. If the map is modified while an iteration over the set is in
795 | * progress (except through the iterator's own {@code remove} operation, or
796 | * through the {@code setValue} operation on a map entry returned by the
797 | * iterator) the results of the iteration are undefined. The set supports
798 | * element removal, which removes the corresponding mapping from the map, via
799 | * the {@code Iterator.remove}, {@code Set.remove}, {@code removeAll},
800 | * {@code retainAll} and {@code clear} operations. It does not support the
801 | * {@code add} or {@code addAll} operations.
802 | */
803 | public Set> entrySet() {
804 | EntrySet es = entrySet;
805 | return (es != null) ? es : (entrySet = new EntrySet());
806 | }
807 |
808 | private transient EntrySet entrySet = null;
809 |
810 | class EntrySet extends AbstractSet> {
811 | public Iterator> iterator() {
812 | return new EntryIterator(getFirstEntry());
813 | }
814 |
815 | public boolean contains(Object o) {
816 | if (!(o instanceof Map.Entry))
817 | return false;
818 | Map.Entry, ?> entry = (Map.Entry, ?>) o;
819 | Object value = entry.getValue();
820 | Entry p = getEntry(entry.getKey());
821 | return p != null && valEquals(p.getValue(), value);
822 | }
823 |
824 | public boolean remove(Object o) {
825 | if (!(o instanceof Map.Entry))
826 | return false;
827 | Map.Entry, ?> entry = (Map.Entry, ?>) o;
828 | Object value = entry.getValue();
829 | Entry p = getEntry(entry.getKey());
830 | if (p != null && valEquals(p.getValue(), value)) {
831 | deleteEntry(p);
832 | return true;
833 | }
834 | return false;
835 | }
836 |
837 | public int size() {
838 | return WAVLTreeMap.this.size();
839 | }
840 |
841 | public void clear() {
842 | WAVLTreeMap.this.clear();
843 | }
844 |
845 | public Spliterator> spliterator() {
846 | return null;
847 | }
848 | }
849 |
850 | /**
851 | * Base class for TreeMap Iterators
852 | */
853 | abstract class PrivateEntryIterator implements Iterator {
854 | Entry next;
855 | Entry lastReturned;
856 | int expectedModCount;
857 |
858 | PrivateEntryIterator(Entry first) {
859 | expectedModCount = modCount;
860 | lastReturned = null;
861 | next = first;
862 | }
863 |
864 | public final boolean hasNext() {
865 | return next != null;
866 | }
867 |
868 | final Entry nextEntry() {
869 | Entry e = next;
870 | if (e == null)
871 | throw new NoSuchElementException();
872 | if (modCount != expectedModCount)
873 | throw new ConcurrentModificationException();
874 | next = successor(e);
875 | lastReturned = e;
876 | return e;
877 | }
878 |
879 | final Entry prevEntry() {
880 | Entry e = next;
881 | if (e == null)
882 | throw new NoSuchElementException();
883 | if (modCount != expectedModCount)
884 | throw new ConcurrentModificationException();
885 | next = predecessor(e);
886 | lastReturned = e;
887 | return e;
888 | }
889 |
890 | public void remove() {
891 | if (lastReturned == null)
892 | throw new IllegalStateException();
893 | if (modCount != expectedModCount)
894 | throw new ConcurrentModificationException();
895 | // deleted entries are replaced by their successors
896 | if (lastReturned.left != null && lastReturned.right != null)
897 | next = lastReturned;
898 | deleteEntry(lastReturned);
899 | expectedModCount = modCount;
900 | lastReturned = null;
901 | }
902 | }
903 |
904 | final class EntryIterator extends PrivateEntryIterator> {
905 | EntryIterator(Entry first) {
906 | super(first);
907 | }
908 |
909 | public Map.Entry next() {
910 | return nextEntry();
911 | }
912 | }
913 | }
--------------------------------------------------------------------------------
/src/main/java/bbst_showdown/AVLTreeMap.java:
--------------------------------------------------------------------------------
1 | package bbst_showdown;
2 |
3 | import java.util.AbstractMap;
4 | import java.util.AbstractSet;
5 | import java.util.Comparator;
6 | import java.util.ConcurrentModificationException;
7 | import java.util.Iterator;
8 | import java.util.Map;
9 | import java.util.NoSuchElementException;
10 | import java.util.Set;
11 | import java.util.Spliterator;
12 |
13 |
14 | /**
15 | * An AVL tree implementation.
16 | *
17 | *
18 | * Because AVL trees enforce stricter balance requirements than red-black trees,
19 | * performance of AVL trees is better than red-black in situations where
20 | * red-black trees become unbalanced.
21 | *
22 | * This code can replace Java's standard TreeMap implementation for improved performance.
23 | *
24 | * Each node in this implementation contains one extra byte for balance factor which holds values of -1,0,1
25 | * after each insert/delete by the original AVL tree definition.
26 | *
27 | * This implementation provides guaranteed log(n) time cost for the
28 | * {@code containsKey}, {@code get}, {@code put} and {@code remove} operations.
29 | *
30 | * @author David McManamon
31 | *
32 | * @param the type of keys maintained by this map
33 | * @param the type of mapped values
34 | */
35 | public class AVLTreeMap extends AbstractMap {
36 |
37 | protected transient Entry root = null;
38 |
39 | /**
40 | * The number of entries in the tree
41 | */
42 | protected transient int size = 0;
43 |
44 | /**
45 | * The comparator used to maintain order in this tree map, or null if it uses
46 | * the natural ordering of its keys.
47 | *
48 | * @serial
49 | */
50 | protected final Comparator super K> comparator;
51 |
52 | /**
53 | * The number of structural modifications to the tree.
54 | */
55 | protected transient int modCount = 0;
56 |
57 | protected transient int rotations = 0;
58 |
59 | /**
60 | * Constructs a new, empty tree map, using the natural ordering of its keys. All
61 | * keys inserted into the map must implement the {@link Comparable} interface.
62 | * Furthermore, all such keys must be mutually comparable:
63 | * {@code k1.compareTo(k2)} must not throw a {@code ClassCastException} for any
64 | * keys {@code k1} and {@code k2} in the map. If the user attempts to put a key
65 | * into the map that violates this constraint (for example, the user attempts to
66 | * put a string key into a map whose keys are integers), the
67 | * {@code put(Object key, Object value)} call will throw a
68 | * {@code ClassCastException}.
69 | */
70 | public AVLTreeMap() {
71 | comparator = null;
72 | }
73 |
74 | /**
75 | * Constructs a new tree map containing the same mappings as the given map,
76 | * ordered according to the natural ordering of its keys. All keys
77 | * inserted into the new map must implement the {@link Comparable} interface.
78 | * Furthermore, all such keys must be mutually comparable:
79 | * {@code k1.compareTo(k2)} must not throw a {@code ClassCastException} for any
80 | * keys {@code k1} and {@code k2} in the map. This method runs in n*log(n) time.
81 | *
82 | * @param m
83 | * the map whose mappings are to be placed in this map
84 | * @throws ClassCastException
85 | * if the keys in m are not {@link Comparable}, or are not mutually
86 | * comparable
87 | * @throws NullPointerException
88 | * if the specified map is null
89 | */
90 | public AVLTreeMap(Map extends K, ? extends V> m) {
91 | comparator = null;
92 | putAll(m);
93 | }
94 |
95 | public int treeHeight() {
96 | return treeHeight(root) - 1;
97 | }
98 |
99 | protected int treeHeight(Entry node) {
100 | if (node == null)
101 | return 0;
102 | return (1 + Math.max(treeHeight(node.left), treeHeight(node.right)));
103 | }
104 |
105 | public int rotations() {
106 | return rotations;
107 | }
108 |
109 | public String toString() {
110 | return "AVL tree of size: " + size + ", height: " + treeHeight() + ", rotations " + rotations;
111 | }
112 |
113 | /**
114 | * Returns the number of key-value mappings in this map.
115 | *
116 | * @return the number of key-value mappings in this map
117 | */
118 | public int size() {
119 | return size;
120 | }
121 |
122 | /**
123 | * Returns the value to which the specified key is mapped, or {@code null} if
124 | * this map contains no mapping for the key.
125 | *
126 | *
127 | * More formally, if this map contains a mapping from a key {@code k} to a value
128 | * {@code v} such that {@code key} compares equal to {@code k} according to the
129 | * map's ordering, then this method returns {@code v}; otherwise it returns
130 | * {@code null}. (There can be at most one such mapping.)
131 | *
132 | *
133 | * A return value of {@code null} does not necessarily indicate that
134 | * the map contains no mapping for the key; it's also possible that the map
135 | * explicitly maps the key to {@code null}. The {@link #containsKey containsKey}
136 | * operation may be used to distinguish these two cases.
137 | *
138 | * @throws ClassCastException
139 | * if the specified key cannot be compared with the keys currently
140 | * in the map
141 | * @throws NullPointerException
142 | * if the specified key is null and this map uses natural ordering,
143 | * or its comparator does not permit null keys
144 | */
145 | public V get(Object key) {
146 | Entry p = getEntry(key);
147 | return (p == null ? null : p.value);
148 | }
149 |
150 | /**
151 | * Node in the Tree. Doubles as a means to pass key-value pairs back to user
152 | * (see Map.Entry).
153 | */
154 | static final class Entry implements Map.Entry {
155 | K key;
156 | V value;
157 | Entry