| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | |
| 2 // for details. All rights reserved. Use of this source code is governed by a | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 /** | |
| 6 * A node in a splay tree. It holds the key, the value and the left | |
| 7 * and right children in the tree. | |
| 8 */ | |
| 9 class SplayTreeNode<K, V> { | |
| 10 SplayTreeNode(K this.key, V this.value); | |
| 11 | |
| 12 K key; | |
| 13 V value; | |
| 14 SplayTreeNode<K, V> left; | |
| 15 SplayTreeNode<K, V> right; | |
| 16 } | |
| 17 | |
| 18 /** | |
| 19 * A splay tree is a self-balancing binary | |
| 20 * search tree with the additional property that recently accessed | |
| 21 * elements are quick to access again. It performs basic operations | |
| 22 * such as insertion, look-up and removal in O(log(n)) amortized time. | |
| 23 * | |
| 24 * This implementation is a Dart version of the JavaScript | |
| 25 * implementation in the V8 project. | |
| 26 */ | |
| 27 class SplayTreeMap<K extends Comparable, V> implements Map<K, V> { | |
| 28 | |
| 29 // The root node of the splay tree. It will contain either the last | |
| 30 // element inserted, or the last element looked up. | |
| 31 SplayTreeNode<K, V> _root; | |
| 32 | |
| 33 // The dummy node used when performing a splay on the tree. It is a | |
| 34 // local field of the class to avoid allocating a node each time a | |
| 35 // splay is performed. | |
| 36 SplayTreeNode<K, V> _dummy; | |
| 37 | |
| 38 // Number of elements in the splay tree. | |
| 39 int _count; | |
| 40 | |
| 41 SplayTreeMap() { | |
| 42 _dummy = new SplayTreeNode<K, V>(null, null); | |
| 43 _count = 0; | |
| 44 } | |
| 45 | |
| 46 /** | |
| 47 * Perform the splay operation for the given key. Moves the node with | |
| 48 * the given key to the top of the tree. If no node has the given | |
| 49 * key, the last node on the search path is moved to the top of the | |
| 50 * tree. This is the simplified top-down splaying algorithm from: | |
| 51 * "Self-adjusting Binary Search Trees" by Sleator and Tarjan. | |
| 52 */ | |
| 53 void splay_(K key) { | |
| 54 if (isEmpty()) return; | |
| 55 | |
| 56 // The right child of the dummy node will hold | |
| 57 // the L tree of the algorithm. The left child of the dummy node | |
| 58 // will hold the R tree of the algorithm. Using a dummy node, left | |
| 59 // and right will always be nodes and we avoid special cases. | |
| 60 SplayTreeNode<K, V> left = _dummy; | |
| 61 SplayTreeNode<K, V> right = _dummy; | |
| 62 SplayTreeNode<K, V> current = _root; | |
| 63 while (true) { | |
| 64 int comp = key.compareTo(current.key); | |
| 65 if (comp < 0) { | |
| 66 if (current.left === null) break; | |
| 67 if (key.compareTo(current.left.key) < 0) { | |
| 68 // Rotate right. | |
| 69 SplayTreeNode<K, V> tmp = current.left; | |
| 70 current.left = tmp.right; | |
| 71 tmp.right = current; | |
| 72 current = tmp; | |
| 73 if (current.left === null) break; | |
| 74 } | |
| 75 // Link right. | |
| 76 right.left = current; | |
| 77 right = current; | |
| 78 current = current.left; | |
| 79 } else if (comp > 0) { | |
| 80 if (current.right === null) break; | |
| 81 if (key.compareTo(current.right.key) > 0) { | |
| 82 // Rotate left. | |
| 83 SplayTreeNode<K, V> tmp = current.right; | |
| 84 current.right = tmp.left; | |
| 85 tmp.left = current; | |
| 86 current = tmp; | |
| 87 if (current.right === null) break; | |
| 88 } | |
| 89 // Link left. | |
| 90 left.right = current; | |
| 91 left = current; | |
| 92 current = current.right; | |
| 93 } else { | |
| 94 break; | |
| 95 } | |
| 96 } | |
| 97 // Assemble. | |
| 98 left.right = current.left; | |
| 99 right.left = current.right; | |
| 100 current.left = _dummy.right; | |
| 101 current.right = _dummy.left; | |
| 102 _root = current; | |
| 103 | |
| 104 _dummy.right = null; | |
| 105 _dummy.left = null; | |
| 106 } | |
| 107 | |
| 108 V operator [](K key) { | |
| 109 if (!isEmpty()) { | |
| 110 splay_(key); | |
| 111 if (_root.key.compareTo(key) == 0) return _root.value; | |
| 112 } | |
| 113 return null; | |
| 114 } | |
| 115 | |
| 116 V remove(K key) { | |
| 117 if (isEmpty()) return null; | |
| 118 splay_(key); | |
| 119 if (_root.key.compareTo(key) != 0) return null; | |
| 120 V value = _root.value; | |
| 121 | |
| 122 _count--; | |
| 123 // assert(_count >= 0); | |
| 124 if (_root.left === null) { | |
| 125 _root = _root.right; | |
| 126 } else { | |
| 127 SplayTreeNode<K, V> right = _root.right; | |
| 128 _root = _root.left; | |
| 129 // Splay to make sure that the new root has an empty right child. | |
| 130 splay_(key); | |
| 131 // Insert the original right child as the right child of the new | |
| 132 // root. | |
| 133 _root.right = right; | |
| 134 } | |
| 135 return value; | |
| 136 } | |
| 137 | |
| 138 void operator []=(K key, V value) { | |
| 139 if (isEmpty()) { | |
| 140 _count++; | |
| 141 _root = new SplayTreeNode(key, value); | |
| 142 return; | |
| 143 } | |
| 144 // Splay on the key to move the last node on the search path for | |
| 145 // the key to the root of the tree. | |
| 146 splay_(key); | |
| 147 if (_root.key.compareTo(key) == 0) { | |
| 148 _root.value = value; | |
| 149 return; | |
| 150 } | |
| 151 SplayTreeNode<K, V> node = new SplayTreeNode(key, value); | |
| 152 // assert(_count >= 0); | |
| 153 _count++; | |
| 154 if (key.compareTo(_root.key) > 0) { | |
| 155 node.left = _root; | |
| 156 node.right = _root.right; | |
| 157 _root.right = null; | |
| 158 } else { | |
| 159 node.right = _root; | |
| 160 node.left = _root.left; | |
| 161 _root.left = null; | |
| 162 } | |
| 163 _root = node; | |
| 164 } | |
| 165 | |
| 166 V putIfAbsent(K key, V ifAbsent()) { | |
| 167 if (containsKey(key)) return this[key]; | |
| 168 V value = ifAbsent(); | |
| 169 this[key] = value; | |
| 170 return value; | |
| 171 } | |
| 172 | |
| 173 bool isEmpty() { | |
| 174 // assert(!((_root === null) && (_count != 0))); | |
| 175 // assert(!((_count == 0) && (_root !== null))); | |
| 176 return (_root === null); | |
| 177 } | |
| 178 | |
| 179 void forEach(void f(K key, V value)) { | |
| 180 List<SplayTreeNode<K, V>> list = new List<SplayTreeNode<K, V>>(); | |
| 181 SplayTreeNode<K, V> current = _root; | |
| 182 while (current !== null) { | |
| 183 if (current.left !== null) { | |
| 184 list.add(current); | |
| 185 current = current.left; | |
| 186 } else { | |
| 187 f(current.key, current.value); | |
| 188 while (current.right === null) { | |
| 189 if (list.isEmpty()) return; | |
| 190 current = list.removeLast(); | |
| 191 f(current.key, current.value); | |
| 192 } | |
| 193 current = current.right; | |
| 194 } | |
| 195 } | |
| 196 } | |
| 197 | |
| 198 int get length() { | |
| 199 return _count; | |
| 200 } | |
| 201 | |
| 202 void clear() { | |
| 203 _root = null; | |
| 204 _count = 0; | |
| 205 } | |
| 206 | |
| 207 bool containsKey(K key) { | |
| 208 if (!isEmpty()) { | |
| 209 splay_(key); | |
| 210 if (_root.key.compareTo(key) == 0) return true; | |
| 211 } | |
| 212 return false; | |
| 213 } | |
| 214 | |
| 215 bool containsValue(V value) { | |
| 216 bool found = false; | |
| 217 bool visit(SplayTreeNode node) { | |
| 218 if (node === null) return false; | |
| 219 if (node.value == value) return true; | |
| 220 return visit(node.left) || visit(node.right); | |
| 221 } | |
| 222 return visit(_root); | |
| 223 } | |
| 224 | |
| 225 Collection<K> getKeys() { | |
| 226 List<K> list = new List<K>(); | |
| 227 forEach((K k, V v) { list.add(k); }); | |
| 228 return list; | |
| 229 } | |
| 230 | |
| 231 Collection<V> getValues() { | |
| 232 List<V> list = new List<V>(); | |
| 233 forEach((K k, V v) { list.add(v); }); | |
| 234 return list; | |
| 235 } | |
| 236 | |
| 237 String toString() { | |
| 238 return Maps.mapToString(this); | |
| 239 } | |
| 240 | |
| 241 /** | |
| 242 * Get the first key in the map. Returns [null] if the map is empty. | |
| 243 */ | |
| 244 K firstKey() { | |
| 245 if (_root === null) return null; | |
| 246 SplayTreeNode<K, V> node = _root; | |
| 247 while (node.left !== null) { | |
| 248 node = node.left; | |
| 249 } | |
| 250 // Maybe implement a splay-method that can splay the minimum without | |
| 251 // performing comparisons. | |
| 252 splay_(node.key); | |
| 253 return node.key; | |
| 254 } | |
| 255 | |
| 256 /** | |
| 257 * Get the last key in the map. Returns [null] if the map is empty. | |
| 258 */ | |
| 259 K lastKey() { | |
| 260 if (_root === null) return null; | |
| 261 SplayTreeNode<K, V> node = _root; | |
| 262 while (node.right !== null) { | |
| 263 node = node.right; | |
| 264 } | |
| 265 // Maybe implement a splay-method that can splay the maximum without | |
| 266 // performing comparisons. | |
| 267 splay_(node.key); | |
| 268 return node.key; | |
| 269 } | |
| 270 | |
| 271 /** | |
| 272 * Get the last key in the map that is strictly smaller than [key]. Returns | |
| 273 * [null] if no key was not found. | |
| 274 */ | |
| 275 K lastKeyBefore(K key) { | |
| 276 splay_(key); | |
| 277 K visit(SplayTreeNode node, K ifEmpty) { | |
| 278 if (node === null) return ifEmpty; | |
| 279 if (node.key.compareTo(key) >= 0) { | |
| 280 return visit(node.left, ifEmpty); | |
| 281 } | |
| 282 if (node.key.compareTo(key) < 0) { | |
| 283 return visit(node.right, node.key); | |
| 284 } | |
| 285 } | |
| 286 return visit(_root, null); | |
| 287 } | |
| 288 | |
| 289 /** | |
| 290 * Get the first key in the map that is strictly larger than [key]. Returns | |
| 291 * [null] if no key was not found. | |
| 292 */ | |
| 293 K firstKeyAfter(K key) { | |
| 294 splay_(key); | |
| 295 K visit(SplayTreeNode node, K ifEmpty) { | |
| 296 if (node === null) return ifEmpty; | |
| 297 if (node.key.compareTo(key) > 0) { | |
| 298 return visit(node.left, node.key); | |
| 299 } | |
| 300 if (node.key.compareTo(key) <= 0) { | |
| 301 return visit(node.right, ifEmpty); | |
| 302 } | |
| 303 } | |
| 304 return visit(_root, null); | |
| 305 } | |
| 306 } | |
| OLD | NEW |