| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 /** | 5 /** |
| 6 * A node in a splay tree. It holds the key, the value and the left | 6 * A node in a splay tree. It holds the key, the value and the left |
| 7 * and right children in the tree. | 7 * and right children in the tree. |
| 8 */ | 8 */ |
| 9 class SplayTreeNode<K, V> { | 9 class SplayTreeNode<K, V> { |
| 10 SplayTreeNode(K k, V v) { | 10 SplayTreeNode(K this.key, V this.value); |
| 11 key = k; | |
| 12 value = v; | |
| 13 } | |
| 14 | 11 |
| 15 K key; | 12 K key; |
| 16 V value; | 13 V value; |
| 17 SplayTreeNode<K, V> left; | 14 SplayTreeNode<K, V> left; |
| 18 SplayTreeNode<K, V> right; | 15 SplayTreeNode<K, V> right; |
| 19 } | 16 } |
| 20 | 17 |
| 21 /** | 18 /** |
| 22 * A splay tree is a self-balancing binary | 19 * A splay tree is a self-balancing binary |
| 23 * search tree with the additional property that recently accessed | 20 * search tree with the additional property that recently accessed |
| 24 * elements are quick to access again. It performs basic operations | 21 * elements are quick to access again. It performs basic operations |
| 25 * such as insertion, look-up and removal in O(log(n)) amortized time. | 22 * such as insertion, look-up and removal in O(log(n)) amortized time. |
| 26 * | 23 * |
| 27 * This implementation is a Dart version of the JavaScript | 24 * This implementation is a Dart version of the JavaScript |
| 28 * implementation in the V8 project. | 25 * implementation in the V8 project. |
| 29 */ | 26 */ |
| 30 class SplayTree<K extends Comparable, V> implements Map<K, V> { | 27 class SplayTreeMap<K extends Comparable, V> implements Map<K, V> { |
| 31 | 28 |
| 32 // The root node of the splay tree. It will contain either the last | 29 // The root node of the splay tree. It will contain either the last |
| 33 // element inserted, or the last element looked up. | 30 // element inserted, or the last element looked up. |
| 34 SplayTreeNode<K, V> _root; | 31 SplayTreeNode<K, V> _root; |
| 35 | 32 |
| 36 // The dummy node used when performing a splay on the tree. It is a | 33 // The dummy node used when performing a splay on the tree. It is a |
| 37 // local field of the class to avoid allocating a node each time a | 34 // local field of the class to avoid allocating a node each time a |
| 38 // splay is performed. | 35 // splay is performed. |
| 39 SplayTreeNode<K, V> _dummy; | 36 SplayTreeNode<K, V> _dummy; |
| 40 | 37 |
| 41 // Number of elements in the splay tree. | 38 // Number of elements in the splay tree. |
| 42 int _count; | 39 int _count; |
| 43 | 40 |
| 44 SplayTree() { | 41 SplayTreeMap() { |
| 45 _dummy = new SplayTreeNode<K, V>(null, null); | 42 _dummy = new SplayTreeNode<K, V>(null, null); |
| 46 _count = 0; | 43 _count = 0; |
| 47 } | 44 } |
| 48 | 45 |
| 49 /** | 46 /** |
| 50 * Perform the splay operation for the given key. Moves the node with | 47 * Perform the splay operation for the given key. Moves the node with |
| 51 * the given key to the top of the tree. If no node has the given | 48 * the given key to the top of the tree. If no node has the given |
| 52 * key, the last node on the search path is moved to the top of the | 49 * key, the last node on the search path is moved to the top of the |
| 53 * tree. This is the simplified top-down splaying algorithm from: | 50 * tree. This is the simplified top-down splaying algorithm from: |
| 54 * "Self-adjusting Binary Search Trees" by Sleator and Tarjan. | 51 * "Self-adjusting Binary Search Trees" by Sleator and Tarjan. |
| 55 */ | 52 */ |
| 56 void splay_(K key) { | 53 void splay_(K key) { |
| 57 if (isEmpty()) return; | 54 if (isEmpty()) return; |
| 58 | 55 |
| 59 // The right child of the dummy node will hold | 56 // The right child of the dummy node will hold |
| 60 // the L tree of the algorithm. The left child of the dummy node | 57 // the L tree of the algorithm. The left child of the dummy node |
| 61 // will hold the R tree of the algorithm. Using a dummy node, left | 58 // will hold the R tree of the algorithm. Using a dummy node, left |
| 62 // and right will always be nodes and we avoid special cases. | 59 // and right will always be nodes and we avoid special cases. |
| 63 SplayTreeNode<K, V> left = _dummy; | 60 SplayTreeNode<K, V> left = _dummy; |
| 64 SplayTreeNode<K, V> right = _dummy; | 61 SplayTreeNode<K, V> right = _dummy; |
| 65 SplayTreeNode<K, V> current = _root; | 62 SplayTreeNode<K, V> current = _root; |
| 66 while (true) { | 63 while (true) { |
| 67 if (key.compareTo(current.key) < 0) { | 64 int comp = key.compareTo(current.key); |
| 65 if (comp < 0) { |
| 68 if (current.left === null) break; | 66 if (current.left === null) break; |
| 69 if (key.compareTo(current.left.key) < 0) { | 67 if (key.compareTo(current.left.key) < 0) { |
| 70 // Rotate right. | 68 // Rotate right. |
| 71 SplayTreeNode<K, V> tmp = current.left; | 69 SplayTreeNode<K, V> tmp = current.left; |
| 72 current.left = tmp.right; | 70 current.left = tmp.right; |
| 73 tmp.right = current; | 71 tmp.right = current; |
| 74 current = tmp; | 72 current = tmp; |
| 75 if (current.left === null) break; | 73 if (current.left === null) break; |
| 76 } | 74 } |
| 77 // Link right. | 75 // Link right. |
| 78 right.left = current; | 76 right.left = current; |
| 79 right = current; | 77 right = current; |
| 80 current = current.left; | 78 current = current.left; |
| 81 } else if (key.compareTo(current.key) > 0) { | 79 } else if (comp > 0) { |
| 82 if (current.right === null) break; | 80 if (current.right === null) break; |
| 83 if (key.compareTo(current.right.key) > 0) { | 81 if (key.compareTo(current.right.key) > 0) { |
| 84 // Rotate left. | 82 // Rotate left. |
| 85 SplayTreeNode<K, V> tmp = current.right; | 83 SplayTreeNode<K, V> tmp = current.right; |
| 86 current.right = tmp.left; | 84 current.right = tmp.left; |
| 87 tmp.left = current; | 85 tmp.left = current; |
| 88 current = tmp; | 86 current = tmp; |
| 89 if (current.right === null) break; | 87 if (current.right === null) break; |
| 90 } | 88 } |
| 91 // Link left. | 89 // Link left. |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 209 bool containsKey(K key) { | 207 bool containsKey(K key) { |
| 210 if (!isEmpty()) { | 208 if (!isEmpty()) { |
| 211 splay_(key); | 209 splay_(key); |
| 212 if (_root.key.compareTo(key) == 0) return true; | 210 if (_root.key.compareTo(key) == 0) return true; |
| 213 } | 211 } |
| 214 return false; | 212 return false; |
| 215 } | 213 } |
| 216 | 214 |
| 217 bool containsValue(V value) { | 215 bool containsValue(V value) { |
| 218 bool found = false; | 216 bool found = false; |
| 219 // Note: Worst performance you can get because we don't have | 217 bool visit(SplayTreeNode node) { |
| 220 // non-local return. | 218 if (node === null) return false; |
| 221 // TODO: optimize this method with a similar code than forEach. | 219 if (node.value == value) return true; |
| 222 forEach((Object k, Object v) { if (value == v) found = true; }); | 220 return visit(node.left) || visit(node.right); |
| 223 return found; | 221 } |
| 222 return visit(_root); |
| 224 } | 223 } |
| 225 | 224 |
| 226 Collection<K> getKeys() { | 225 Collection<K> getKeys() { |
| 227 List<K> list = new List<K>(); | 226 List<K> list = new List<K>(); |
| 228 forEach((K k, V v) { list.add(k); }); | 227 forEach((K k, V v) { list.add(k); }); |
| 229 return list; | 228 return list; |
| 230 } | 229 } |
| 231 | 230 |
| 232 Collection<V> getValues() { | 231 Collection<V> getValues() { |
| 233 List<V> list = new List<V>(); | 232 List<V> list = new List<V>(); |
| 234 forEach((K k, V v) { list.add(v); }); | 233 forEach((K k, V v) { list.add(v); }); |
| 235 return list; | 234 return list; |
| 236 } | 235 } |
| 237 | 236 |
| 238 String toString() { | 237 String toString() { |
| 239 return Maps.mapToString(this); | 238 return Maps.mapToString(this); |
| 240 } | 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); |
| 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); |
| 305 } |
| 241 } | 306 } |
| OLD | NEW |