Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2171)

Side by Side Diff: sdk/lib/collection/splay_tree.dart

Issue 12260058: Update SplayTreeMap implementation. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Address comments. Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 part of dart.collection; 5 part of dart.collection;
6 6
7 /** 7 /**
8 * A node in a splay tree. It holds the key, the value and the left 8 * A node in a splay tree. It holds the key, the value and the left
9 * and right children in the tree. 9 * and right children in the tree.
10 */ 10 */
11 class SplayTreeNode<K, V> { 11 class SplayTreeNode<K, V> {
12 SplayTreeNode(K this.key, V this.value); 12 final K key;
13
14 K key;
15 V value; 13 V value;
16 SplayTreeNode<K, V> left; 14 SplayTreeNode<K, V> left;
17 SplayTreeNode<K, V> right; 15 SplayTreeNode<K, V> right;
16
17 SplayTreeNode(K this.key, V this.value);
18 } 18 }
19 19
20 /** 20 /**
21 * A splay tree is a self-balancing binary 21 * A splay tree is a self-balancing binary
22 * search tree with the additional property that recently accessed 22 * search tree with the additional property that recently accessed
23 * elements are quick to access again. It performs basic operations 23 * elements are quick to access again. It performs basic operations
24 * such as insertion, look-up and removal in O(log(n)) amortized time. 24 * such as insertion, look-up and removal in O(log(n)) amortized time.
25 * 25 *
26 * This implementation is a Dart version of the JavaScript 26 * This implementation is a Dart version of the JavaScript
27 * implementation in the V8 project. 27 * implementation in the V8 project.
28 */ 28 */
29 class SplayTreeMap<K extends Comparable, V> implements Map<K, V> { 29 class SplayTreeMap<K extends Comparable, V> implements Map<K, V> {
30 30
31 // The root node of the splay tree. It will contain either the last 31 // The root node of the splay tree. It will contain either the last
32 // element inserted, or the last element looked up. 32 // element inserted, or the last element looked up.
33 SplayTreeNode<K, V> _root; 33 SplayTreeNode<K, V> _root;
34 34
35 // The dummy node used when performing a splay on the tree. It is a 35 // The dummy node used when performing a splay on the tree. It is a
36 // local field of the class to avoid allocating a node each time a 36 // local field of the class to avoid allocating a node each time a
37 // splay is performed. 37 // splay is performed.
38 SplayTreeNode<K, V> _dummy; 38 SplayTreeNode<K, V> _dummy;
39 39
40 // Number of elements in the splay tree. 40 // Number of elements in the splay tree.
41 int _count; 41 int _count;
42 42
43 SplayTreeMap() { 43 /**
44 _dummy = new SplayTreeNode<K, V>(null, null); 44 * Counter incremented whenever the keys in the map changes.
45 *
46 * Used to detect concurrent modifications.
47 */
48 int _modificationCount = 0;
49 /**
50 * Counter incremented whenever the tree structure changes.
51 *
52 * Used to detect that an in-place traversal cannot use
53 * cached information that relies on the tree structure.
54 */
55 int _splayCount = 0;
56
57 SplayTreeMap() :
58 _dummy = new SplayTreeNode<K, V>(null, null),
45 _count = 0; 59 _count = 0;
46 }
47 60
48 /** 61 /**
49 * Perform the splay operation for the given key. Moves the node with 62 * Perform the splay operation for the given key. Moves the node with
50 * the given key to the top of the tree. If no node has the given 63 * the given key to the top of the tree. If no node has the given
51 * key, the last node on the search path is moved to the top of the 64 * key, the last node on the search path is moved to the top of the
52 * tree. This is the simplified top-down splaying algorithm from: 65 * tree. This is the simplified top-down splaying algorithm from:
53 * "Self-adjusting Binary Search Trees" by Sleator and Tarjan. 66 * "Self-adjusting Binary Search Trees" by Sleator and Tarjan.
67 *
68 * Returns the result of comparing the new root of the tree to [key].
69 * Returns -1 if the table is empty.
54 */ 70 */
55 void splay_(K key) { 71 int _splay(K key) {
56 if (isEmpty) return; 72 if (_root == null) return -1;
57 73
58 // The right child of the dummy node will hold 74 // The right child of the dummy node will hold
59 // the L tree of the algorithm. The left child of the dummy node 75 // the L tree of the algorithm. The left child of the dummy node
60 // will hold the R tree of the algorithm. Using a dummy node, left 76 // will hold the R tree of the algorithm. Using a dummy node, left
61 // and right will always be nodes and we avoid special cases. 77 // and right will always be nodes and we avoid special cases.
62 SplayTreeNode<K, V> left = _dummy; 78 SplayTreeNode<K, V> left = _dummy;
63 SplayTreeNode<K, V> right = _dummy; 79 SplayTreeNode<K, V> right = _dummy;
64 SplayTreeNode<K, V> current = _root; 80 SplayTreeNode<K, V> current = _root;
81 int comp;
65 while (true) { 82 while (true) {
66 int comp = key.compareTo(current.key); 83 comp = current.key.compareTo(key);
67 if (comp < 0) { 84 if (comp > 0) {
68 if (current.left == null) break; 85 if (current.left == null) break;
69 if (key.compareTo(current.left.key) < 0) { 86 comp = current.left.key.compareTo(key);
87 if (comp > 0) {
70 // Rotate right. 88 // Rotate right.
71 SplayTreeNode<K, V> tmp = current.left; 89 SplayTreeNode<K, V> tmp = current.left;
72 current.left = tmp.right; 90 current.left = tmp.right;
73 tmp.right = current; 91 tmp.right = current;
74 current = tmp; 92 current = tmp;
75 if (current.left == null) break; 93 if (current.left == null) break;
76 } 94 }
77 // Link right. 95 // Link right.
78 right.left = current; 96 right.left = current;
79 right = current; 97 right = current;
80 current = current.left; 98 current = current.left;
81 } else if (comp > 0) { 99 } else if (comp < 0) {
82 if (current.right == null) break; 100 if (current.right == null) break;
83 if (key.compareTo(current.right.key) > 0) { 101 comp = current.right.key.compareTo(key);
102 if (comp < 0) {
84 // Rotate left. 103 // Rotate left.
85 SplayTreeNode<K, V> tmp = current.right; 104 SplayTreeNode<K, V> tmp = current.right;
86 current.right = tmp.left; 105 current.right = tmp.left;
87 tmp.left = current; 106 tmp.left = current;
88 current = tmp; 107 current = tmp;
89 if (current.right == null) break; 108 if (current.right == null) break;
90 } 109 }
91 // Link left. 110 // Link left.
92 left.right = current; 111 left.right = current;
93 left = current; 112 left = current;
94 current = current.right; 113 current = current.right;
95 } else { 114 } else {
96 break; 115 break;
97 } 116 }
98 } 117 }
99 // Assemble. 118 // Assemble.
100 left.right = current.left; 119 left.right = current.left;
101 right.left = current.right; 120 right.left = current.right;
102 current.left = _dummy.right; 121 current.left = _dummy.right;
103 current.right = _dummy.left; 122 current.right = _dummy.left;
104 _root = current; 123 _root = current;
105 124
106 _dummy.right = null; 125 _dummy.right = null;
107 _dummy.left = null; 126 _dummy.left = null;
127 _splayCount++;
128 return comp;
108 } 129 }
109 130
110 V operator [](K key) { 131 V operator [](K key) {
111 if (!isEmpty) { 132 if (_root != null) {
112 splay_(key); 133 int comp = _splay(key);
113 if (_root.key.compareTo(key) == 0) return _root.value; 134 if (comp == 0) return _root.value;
114 } 135 }
115 return null; 136 return null;
116 } 137 }
117 138
118 V remove(K key) { 139 V remove(K key) {
119 if (isEmpty) return null; 140 if (_root == null) return null;
120 splay_(key); 141 int comp = _splay(key);
121 if (_root.key.compareTo(key) != 0) return null; 142 if (comp != 0) return null;
122 V value = _root.value; 143 V value = _root.value;
123 144
124 _count--; 145 _count--;
125 // assert(_count >= 0); 146 // assert(_count >= 0);
126 if (_root.left == null) { 147 if (_root.left == null) {
127 _root = _root.right; 148 _root = _root.right;
128 } else { 149 } else {
129 SplayTreeNode<K, V> right = _root.right; 150 SplayTreeNode<K, V> right = _root.right;
130 _root = _root.left; 151 _root = _root.left;
131 // Splay to make sure that the new root has an empty right child. 152 // Splay to make sure that the new root has an empty right child.
132 splay_(key); 153 _splay(key);
133 // Insert the original right child as the right child of the new 154 // Insert the original right child as the right child of the new
134 // root. 155 // root.
135 _root.right = right; 156 _root.right = right;
136 } 157 }
158 _modificationCount++;
137 return value; 159 return value;
138 } 160 }
139 161
140 void operator []=(K key, V value) { 162 void operator []=(K key, V value) {
141 if (isEmpty) { 163 if (_root == null) {
142 _count++; 164 _count++;
143 _root = new SplayTreeNode(key, value); 165 _root = new SplayTreeNode(key, value);
166 _modificationCount++;
144 return; 167 return;
145 } 168 }
146 // Splay on the key to move the last node on the search path for 169 // Splay on the key to move the last node on the search path for
147 // the key to the root of the tree. 170 // the key to the root of the tree.
148 splay_(key); 171 int comp = _splay(key);
149 if (_root.key.compareTo(key) == 0) { 172 if (comp == 0) {
150 _root.value = value; 173 _root.value = value;
151 return; 174 return;
152 } 175 }
176 _addNewRoot(key, value, comp);
177 }
178
179 /**
180 * Adds a new root node with the given [key] or [value].
181 *
182 * The [comp] value is the result of comparing the existing root's key
183 * with key.
184 */
185 void _addNewRoot(K key, V value, int comp) {
153 SplayTreeNode<K, V> node = new SplayTreeNode(key, value); 186 SplayTreeNode<K, V> node = new SplayTreeNode(key, value);
154 // assert(_count >= 0); 187 // assert(_count >= 0);
155 _count++; 188 _count++;
156 if (key.compareTo(_root.key) > 0) { 189 if (comp < 0) {
157 node.left = _root; 190 node.left = _root;
158 node.right = _root.right; 191 node.right = _root.right;
159 _root.right = null; 192 _root.right = null;
160 } else { 193 } else {
161 node.right = _root; 194 node.right = _root;
162 node.left = _root.left; 195 node.left = _root.left;
163 _root.left = null; 196 _root.left = null;
164 } 197 }
165 _root = node; 198 _root = node;
199 _modificationCount++;
166 } 200 }
167 201
168 V putIfAbsent(K key, V ifAbsent()) { 202 V putIfAbsent(K key, V ifAbsent()) {
169 if (containsKey(key)) return this[key]; 203 if (_root == null) {
204 V value = ifAbsent();
205 if (_root != null) {
206 throw new ConcurrentModificationError(this);
207 }
208 _root = new SplayTreeNode(key, value);
209 _count++;
210 _modificationCount++;
211 return value;
212 }
213 int comp = _splay(key);
214 if (comp == 0) return _root.value;
215 int modificationCount = _modificationCount;
216 int splayCount = _splayCount;
170 V value = ifAbsent(); 217 V value = ifAbsent();
171 this[key] = value; 218 if (modificationCount != _modificationCount) {
219 throw new ConcurrentModificationError(this);
220 }
221 if (splayCount != _splayCount) {
222 comp = _splay(key);
223 // Key is still not there, otherwise _modificationCount would be changed.
224 assert(comp != 0);
225 }
226 _addNewRoot(key, value, comp);
172 return value; 227 return value;
173 } 228 }
174 229
175 bool get isEmpty { 230 bool get isEmpty {
176 // assert(!((_root == null) && (_count != 0))); 231 // assert(!((_root == null) && (_count != 0)));
177 // assert(!((_count == 0) && (_root != null))); 232 // assert(!((_count == 0) && (_root != null)));
178 return (_root == null); 233 return (_root == null);
179 } 234 }
180 235
181 void forEach(void f(K key, V value)) { 236 void forEach(void f(K key, V value)) {
182 List<SplayTreeNode<K, V>> list = new List<SplayTreeNode<K, V>>(); 237 Iterator<SplayTreeNode<K, V>> nodes =
183 SplayTreeNode<K, V> current = _root; 238 new _SplayTreeNodeIterator<K, V>(this);
184 while (current != null) { 239 while (nodes.moveNext()) {
185 if (current.left != null) { 240 SplayTreeNode<K, V> node = nodes.current;
186 list.add(current); 241 f(node.key, node.value);
187 current = current.left;
188 } else {
189 f(current.key, current.value);
190 while (current.right == null) {
191 if (list.isEmpty) return;
192 current = list.removeLast();
193 f(current.key, current.value);
194 }
195 current = current.right;
196 }
197 } 242 }
198 } 243 }
199 244
200 int get length { 245 int get length {
201 return _count; 246 return _count;
202 } 247 }
203 248
204 void clear() { 249 void clear() {
205 _root = null; 250 _root = null;
206 _count = 0; 251 _count = 0;
207 } 252 }
208 253
209 bool containsKey(K key) { 254 bool containsKey(K key) {
210 if (!isEmpty) { 255 return _splay(key) == 0;
211 splay_(key);
212 if (_root.key.compareTo(key) == 0) return true;
213 }
214 return false;
215 } 256 }
216 257
217 bool containsValue(V value) { 258 bool containsValue(V value) {
218 bool found = false; 259 bool found = false;
219 bool visit(SplayTreeNode node) { 260 bool visit(SplayTreeNode node) {
220 if (node == null) return false; 261 if (node == null) return false;
221 if (node.value == value) return true; 262 if (node.value == value) return true;
263 // TODO(lrn): Do we want to handle the case where node.value.operator==
264 // modifies the map?
222 return visit(node.left) || visit(node.right); 265 return visit(node.left) || visit(node.right);
223 } 266 }
224 return visit(_root); 267 return visit(_root);
225 } 268 }
226 269
227 Collection<K> get keys { 270 Iterable<K> get keys => new _SplayTreeKeyIterable(this);
228 List<K> list = new List<K>();
229 forEach((K k, V v) { list.add(k); });
230 return list;
231 }
232 271
233 Collection<V> get values { 272 Iterable<V> get values => new _SplayTreeValueIterable(this);
234 List<V> list = new List<V>();
235 forEach((K k, V v) { list.add(v); });
236 return list;
237 }
238 273
239 String toString() { 274 String toString() {
240 return Maps.mapToString(this); 275 return Maps.mapToString(this);
241 } 276 }
242 277
243 /** 278 /**
244 * Get the first key in the map. Returns [null] if the map is empty. 279 * Get the first key in the map. Returns [null] if the map is empty.
245 */ 280 */
246 K firstKey() { 281 K firstKey() {
247 if (_root == null) return null; 282 if (_root == null) return null;
248 SplayTreeNode<K, V> node = _root; 283 SplayTreeNode<K, V> node = _root;
249 while (node.left != null) { 284 while (node.left != null) {
250 node = node.left; 285 node = node.left;
251 } 286 }
252 // Maybe implement a splay-method that can splay the minimum without 287 // Maybe implement a splay-method that can splay the minimum without
253 // performing comparisons. 288 // performing comparisons.
254 splay_(node.key); 289 _splay(node.key);
255 return node.key; 290 return node.key;
256 } 291 }
257 292
258 /** 293 /**
259 * Get the last key in the map. Returns [null] if the map is empty. 294 * Get the last key in the map. Returns [null] if the map is empty.
260 */ 295 */
261 K lastKey() { 296 K lastKey() {
262 if (_root == null) return null; 297 if (_root == null) return null;
263 SplayTreeNode<K, V> node = _root; 298 SplayTreeNode<K, V> node = _root;
264 while (node.right != null) { 299 while (node.right != null) {
265 node = node.right; 300 node = node.right;
266 } 301 }
267 // Maybe implement a splay-method that can splay the maximum without 302 // Maybe implement a splay-method that can splay the maximum without
268 // performing comparisons. 303 // performing comparisons.
269 splay_(node.key); 304 _splay(node.key);
270 return node.key; 305 return node.key;
271 } 306 }
272 307
273 /** 308 /**
274 * Get the last key in the map that is strictly smaller than [key]. Returns 309 * Get the last key in the map that is strictly smaller than [key]. Returns
275 * [null] if no key was not found. 310 * [null] if no key was not found.
276 */ 311 */
277 K lastKeyBefore(K key) { 312 K lastKeyBefore(K key) {
278 splay_(key); 313 if (_root == null) return null;
279 K visit(SplayTreeNode node, K ifEmpty) { 314 int comp = _splay(key);
280 if (node == null) return ifEmpty; 315 if (comp < 0) return _root.key;
281 if (node.key.compareTo(key) >= 0) { 316 SplayTreeNode<K, V> node = _root.left;
282 return visit(node.left, ifEmpty); 317 if (node == null) return null;
283 } 318 while (node.right != null) {
284 if (node.key.compareTo(key) < 0) { 319 node = node.right;
285 return visit(node.right, node.key);
286 }
287 } 320 }
288 return visit(_root, null); 321 return node.key;
289 } 322 }
290 323
291 /** 324 /**
292 * Get the first key in the map that is strictly larger than [key]. Returns 325 * Get the first key in the map that is strictly larger than [key]. Returns
293 * [null] if no key was not found. 326 * [null] if no key was not found.
294 */ 327 */
295 K firstKeyAfter(K key) { 328 K firstKeyAfter(K key) {
296 splay_(key); 329 if (_root == null) return null;
297 K visit(SplayTreeNode node, K ifEmpty) { 330 int comp = _splay(key);
298 if (node == null) return ifEmpty; 331 if (comp > 0) return _root.key;
299 if (node.key.compareTo(key) > 0) { 332 SplayTreeNode<K, V> node = _root.right;
300 return visit(node.left, node.key); 333 if (node == null) return null;
301 } 334 while (node.left != null) {
302 if (node.key.compareTo(key) <= 0) { 335 node = node.left;
303 return visit(node.right, ifEmpty);
304 }
305 } 336 }
306 return visit(_root, null); 337 return node.key;
307 } 338 }
308 } 339 }
340
341 abstract class _SplayTreeIterator<T> implements Iterator<T> {
342 final SplayTreeMap _map;
343 /**
344 * Worklist of nodes to visit.
345 *
346 * These nodes have been passed over on the way down in a
347 * depth-first left-to-right traversal. Visiting each node,
348 * and their right subtrees will visit the remainder of
349 * the nodes of a full traversal.
350 *
351 * Only valid as long as the original tree map isn't reordered.
352 */
353 final List<SplayTreeNode> _workList = <SplayTreeNode>[];
354
355 /**
356 * Original modification counter of [_map].
357 *
358 * Incremented on [_map] when a key is added or removed.
359 * If it changes, iteration is aborted.
360 */
361 final int _modificationCount;
362
363 /**
364 * Count of splay operations on [_map] when [_workList] was built.
365 *
366 * If the splay count on [_map] increases, [_workList] becomes invalid.
367 */
368 int _splayCount;
369
370 /** Current node. */
371 SplayTreeNode _currentNode;
372
373 _SplayTreeIterator(SplayTreeMap map)
374 : _map = map,
375 _modificationCount = map._modificationCount,
376 _splayCount = map._splayCount {
377 _findLeftMostDescendent(map._root);
378 }
379
380 T get current {
381 if (_currentNode == null) return null;
382 return _getValue(_currentNode);
383 }
384
385 void _findLeftMostDescendent(SplayTreeNode node) {
386 while (node != null) {
387 _workList.add(node);
388 node = node.left;
389 }
390 }
391
392 /**
393 * Called when the tree structure of the map has changed.
394 *
395 * This can be caused by a splay operation.
396 * If the key-set changes, iteration is aborted before getting
397 * here, so we know that the keys are the same as before, it's
398 * only the tree that has been reordered.
399 */
400 void _rebuildWorkList(SplayTreeNode currentNode) {
401 assert(!_workList.isEmpty);
402 _workList.clear();
403 if (currentNode == null) {
404 _findLeftMostDescendent(_map._root);
405 } else {
406 _map._splay(currentNode.key);
407 _findLeftMostDescendent(_map._root.right);
408 assert(!_workList.isEmpty);
409 }
410 }
411
412 bool moveNext() {
413 if (_modificationCount != _map._modificationCount) {
414 throw new ConcurrentModificationError(_map);
415 }
416 // Picks the next element in the worklist as current.
417 // Updates the worklist with the left-most path of the current node's
418 // right-hand child.
419 // If the worklist is no longer valid (after a splay), it is rebuild
420 // from scratch.
421 if (_workList.isEmpty) {
422 _currentNode = null;
423 return false;
424 }
425 if (_map._splayCount != _splayCount) {
426 _rebuildWorkList(_currentNode);
427 }
428 _currentNode = _workList.removeLast();
429 _findLeftMostDescendent(_currentNode.right);
430 return true;
431 }
432
433 T _getValue(SplayTreeNode node);
434 }
435
436
437 class _SplayTreeKeyIterable<K, V> extends Iterable<K> {
438 SplayTreeMap<K, V> _map;
439 _SplayTreeKeyIterable(this._map);
440 Iterator<K> get iterator => new _SplayTreeKeyIterator<K, V>(_map);
441 }
442
443 class _SplayTreeValueIterable<K, V> extends Iterable<V> {
444 SplayTreeMap<K, V> _map;
445 _SplayTreeValueIterable(this._map) ;
446 Iterator<V> get iterator => new _SplayTreeValueIterator<K, V>(_map);
447 }
448
449 class _SplayTreeKeyIterator<K, V> extends _SplayTreeIterator<K> {
450 _SplayTreeKeyIterator(SplayTreeMap<K, V> map): super(map);
451 K _getValue(SplayTreeNode node) => node.key;
452 }
453
454 class _SplayTreeValueIterator<K, V> extends _SplayTreeIterator<V> {
455 _SplayTreeValueIterator(SplayTreeMap<K, V> map): super(map);
456 V _getValue(SplayTreeNode node) => node.value;
457 }
458
459 class _SplayTreeNodeIterator<K, V>
460 extends _SplayTreeIterator<SplayTreeNode<K, V>> {
461 _SplayTreeNodeIterator(SplayTreeMap<K, V> map): super(map);
462 SplayTreeNode<K, V> _getValue(SplayTreeNode node) => node;
463 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698