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

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: 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
floitsch 2013/02/15 10:04:49 unfinished sentence.
Lasse Reichstein Nielsen 2013/02/15 13:46:37 Finished.
53 */
54 int _splayCount = 0;
55
56 SplayTreeMap() :
57 _dummy = new SplayTreeNode<K, V>(null, null),
45 _count = 0; 58 _count = 0;
46 }
47 59
48 /** 60 /**
49 * Perform the splay operation for the given key. Moves the node with 61 * 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 62 * 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 63 * 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: 64 * tree. This is the simplified top-down splaying algorithm from:
53 * "Self-adjusting Binary Search Trees" by Sleator and Tarjan. 65 * "Self-adjusting Binary Search Trees" by Sleator and Tarjan.
66 *
67 * Returns the result of comparing the new root of the tree to [key].
68 * Returns -1 if the table is empty.
54 */ 69 */
55 void splay_(K key) { 70 int _splay(K key) {
56 if (isEmpty) return; 71 if (_root == null) return -1;
57 72
58 // The right child of the dummy node will hold 73 // The right child of the dummy node will hold
59 // the L tree of the algorithm. The left child of the dummy node 74 // 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 75 // 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. 76 // and right will always be nodes and we avoid special cases.
62 SplayTreeNode<K, V> left = _dummy; 77 SplayTreeNode<K, V> left = _dummy;
63 SplayTreeNode<K, V> right = _dummy; 78 SplayTreeNode<K, V> right = _dummy;
64 SplayTreeNode<K, V> current = _root; 79 SplayTreeNode<K, V> current = _root;
80 int comp;
65 while (true) { 81 while (true) {
66 int comp = key.compareTo(current.key); 82 comp = current.key.compareTo(key);
67 if (comp < 0) { 83 if (comp > 0) {
68 if (current.left == null) break; 84 if (current.left == null) break;
69 if (key.compareTo(current.left.key) < 0) { 85 comp = current.left.key.compareTo(key);
86 if (comp > 0) {
70 // Rotate right. 87 // Rotate right.
71 SplayTreeNode<K, V> tmp = current.left; 88 SplayTreeNode<K, V> tmp = current.left;
72 current.left = tmp.right; 89 current.left = tmp.right;
73 tmp.right = current; 90 tmp.right = current;
74 current = tmp; 91 current = tmp;
75 if (current.left == null) break; 92 if (current.left == null) break;
76 } 93 }
77 // Link right. 94 // Link right.
78 right.left = current; 95 right.left = current;
79 right = current; 96 right = current;
80 current = current.left; 97 current = current.left;
81 } else if (comp > 0) { 98 } else if (comp < 0) {
82 if (current.right == null) break; 99 if (current.right == null) break;
83 if (key.compareTo(current.right.key) > 0) { 100 comp = current.right.key.compareTo(key);
101 if (comp < 0) {
84 // Rotate left. 102 // Rotate left.
85 SplayTreeNode<K, V> tmp = current.right; 103 SplayTreeNode<K, V> tmp = current.right;
86 current.right = tmp.left; 104 current.right = tmp.left;
87 tmp.left = current; 105 tmp.left = current;
88 current = tmp; 106 current = tmp;
89 if (current.right == null) break; 107 if (current.right == null) break;
90 } 108 }
91 // Link left. 109 // Link left.
92 left.right = current; 110 left.right = current;
93 left = current; 111 left = current;
94 current = current.right; 112 current = current.right;
95 } else { 113 } else {
96 break; 114 break;
97 } 115 }
98 } 116 }
99 // Assemble. 117 // Assemble.
100 left.right = current.left; 118 left.right = current.left;
101 right.left = current.right; 119 right.left = current.right;
102 current.left = _dummy.right; 120 current.left = _dummy.right;
103 current.right = _dummy.left; 121 current.right = _dummy.left;
104 _root = current; 122 _root = current;
105 123
106 _dummy.right = null; 124 _dummy.right = null;
107 _dummy.left = null; 125 _dummy.left = null;
126 _splayCount++;
127 return comp;
108 } 128 }
109 129
110 V operator [](K key) { 130 V operator [](K key) {
111 if (!isEmpty) { 131 if (_root != null) {
112 splay_(key); 132 int comp = _splay(key);
113 if (_root.key.compareTo(key) == 0) return _root.value; 133 if (comp == 0) return _root.value;
114 } 134 }
115 return null; 135 return null;
116 } 136 }
117 137
118 V remove(K key) { 138 V remove(K key) {
119 if (isEmpty) return null; 139 if (_root == null) return null;
120 splay_(key); 140 int comp = _splay(key);
121 if (_root.key.compareTo(key) != 0) return null; 141 if (comp != 0) return null;
122 V value = _root.value; 142 V value = _root.value;
123 143
124 _count--; 144 _count--;
125 // assert(_count >= 0); 145 // assert(_count >= 0);
126 if (_root.left == null) { 146 if (_root.left == null) {
127 _root = _root.right; 147 _root = _root.right;
128 } else { 148 } else {
129 SplayTreeNode<K, V> right = _root.right; 149 SplayTreeNode<K, V> right = _root.right;
130 _root = _root.left; 150 _root = _root.left;
131 // Splay to make sure that the new root has an empty right child. 151 // Splay to make sure that the new root has an empty right child.
132 splay_(key); 152 _splay(key);
133 // Insert the original right child as the right child of the new 153 // Insert the original right child as the right child of the new
134 // root. 154 // root.
135 _root.right = right; 155 _root.right = right;
136 } 156 }
157 _modificationCount++;
137 return value; 158 return value;
138 } 159 }
139 160
140 void operator []=(K key, V value) { 161 void operator []=(K key, V value) {
141 if (isEmpty) { 162 if (_root == null) {
142 _count++; 163 _count++;
143 _root = new SplayTreeNode(key, value); 164 _root = new SplayTreeNode(key, value);
165 _modificationCount++;
144 return; 166 return;
145 } 167 }
146 // Splay on the key to move the last node on the search path for 168 // Splay on the key to move the last node on the search path for
147 // the key to the root of the tree. 169 // the key to the root of the tree.
148 splay_(key); 170 int comp = _splay(key);
149 if (_root.key.compareTo(key) == 0) { 171 if (comp == 0) {
150 _root.value = value; 172 _root.value = value;
151 return; 173 return;
152 } 174 }
175 _addNewRoot(key, value, comp);
176 }
177
178 /**
179 * Adds a new root node with the given [key] or [value].
180 *
181 * The [comp] value is the result of comparing the existing root's key
182 * with key.
183 */
184 void _addNewRoot(K key, V value, int comp) {
153 SplayTreeNode<K, V> node = new SplayTreeNode(key, value); 185 SplayTreeNode<K, V> node = new SplayTreeNode(key, value);
154 // assert(_count >= 0); 186 // assert(_count >= 0);
155 _count++; 187 _count++;
156 if (key.compareTo(_root.key) > 0) { 188 if (comp < 0) {
157 node.left = _root; 189 node.left = _root;
158 node.right = _root.right; 190 node.right = _root.right;
159 _root.right = null; 191 _root.right = null;
160 } else { 192 } else {
161 node.right = _root; 193 node.right = _root;
162 node.left = _root.left; 194 node.left = _root.left;
163 _root.left = null; 195 _root.left = null;
164 } 196 }
165 _root = node; 197 _root = node;
198 _modificationCount++;
166 } 199 }
167 200
168 V putIfAbsent(K key, V ifAbsent()) { 201 V putIfAbsent(K key, V ifAbsent()) {
169 if (containsKey(key)) return this[key]; 202 if (_root == null) {
203 V value = ifAbsent();
204 if (_root != null) {
205 throw new ConcurrentModificationError(this);
206 }
207 _root = new SplayTreeNode(key, value);
208 _count++;
209 _modificationCount++;
210 return value;
211 }
212 int comp = _splay(key);
213 if (comp == 0) return _root.value;
214 int modificationCount = _modificationCount;
215 int splayCount = _splayCount;
170 V value = ifAbsent(); 216 V value = ifAbsent();
171 this[key] = value; 217 if (modificationCount != _modificationCount) {
218 throw new ConcurrentModificationError(this);
219 }
220 if (splayCount != _splayCount) {
221 comp = _splay(key);
222 if (comp == 0) {
floitsch 2013/02/15 10:04:49 Can this happen? We didn't find the comp before, a
Lasse Reichstein Nielsen 2013/02/15 13:46:37 Good catch.
223 _root.value = value;
224 return value;
225 }
226 }
227 _addNewRoot(key, value, comp);
172 return value; 228 return value;
173 } 229 }
174 230
175 bool get isEmpty { 231 bool get isEmpty {
176 // assert(!((_root == null) && (_count != 0))); 232 // assert(!((_root == null) && (_count != 0)));
177 // assert(!((_count == 0) && (_root != null))); 233 // assert(!((_count == 0) && (_root != null)));
178 return (_root == null); 234 return (_root == null);
179 } 235 }
180 236
181 void forEach(void f(K key, V value)) { 237 void forEach(void f(K key, V value)) {
182 List<SplayTreeNode<K, V>> list = new List<SplayTreeNode<K, V>>(); 238 Iterator<SplayTreeNode<K, V>> nodes =
183 SplayTreeNode<K, V> current = _root; 239 new _SplayTreeNodeIterator<K, V>(this);
184 while (current != null) { 240 while (nodes.moveNext()) {
185 if (current.left != null) { 241 SplayTreeNode<K, V> node = nodes.current;
186 list.add(current); 242 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 } 243 }
198 } 244 }
199 245
200 int get length { 246 int get length {
201 return _count; 247 return _count;
202 } 248 }
203 249
204 void clear() { 250 void clear() {
205 _root = null; 251 _root = null;
206 _count = 0; 252 _count = 0;
207 } 253 }
208 254
209 bool containsKey(K key) { 255 bool containsKey(K key) {
210 if (!isEmpty) { 256 return _splay(key) == 0;
211 splay_(key);
212 if (_root.key.compareTo(key) == 0) return true;
213 }
214 return false;
215 } 257 }
216 258
217 bool containsValue(V value) { 259 bool containsValue(V value) {
218 bool found = false; 260 bool found = false;
219 bool visit(SplayTreeNode node) { 261 bool visit(SplayTreeNode node) {
220 if (node == null) return false; 262 if (node == null) return false;
221 if (node.value == value) return true; 263 if (node.value == value) return true;
264 // TODO(lrn): Do we want to handle the case where node.value.operator==
floitsch 2013/02/15 10:04:49 I guess we need to eventually.
Lasse Reichstein Nielsen 2013/02/15 13:46:37 We have to do the same for compareTo in _splay. Th
floitsch 2013/02/15 13:58:25 Let's look at that later.
265 // modifies the map?
222 return visit(node.left) || visit(node.right); 266 return visit(node.left) || visit(node.right);
223 } 267 }
224 return visit(_root); 268 return visit(_root);
225 } 269 }
226 270
227 Collection<K> get keys { 271 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 272
233 Collection<V> get values { 273 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 274
239 String toString() { 275 String toString() {
240 return Maps.mapToString(this); 276 return Maps.mapToString(this);
241 } 277 }
242 278
243 /** 279 /**
244 * Get the first key in the map. Returns [null] if the map is empty. 280 * Get the first key in the map. Returns [null] if the map is empty.
245 */ 281 */
246 K firstKey() { 282 K firstKey() {
247 if (_root == null) return null; 283 if (_root == null) return null;
248 SplayTreeNode<K, V> node = _root; 284 SplayTreeNode<K, V> node = _root;
249 while (node.left != null) { 285 while (node.left != null) {
250 node = node.left; 286 node = node.left;
251 } 287 }
252 // Maybe implement a splay-method that can splay the minimum without 288 // Maybe implement a splay-method that can splay the minimum without
253 // performing comparisons. 289 // performing comparisons.
254 splay_(node.key); 290 _splay(node.key);
255 return node.key; 291 return node.key;
256 } 292 }
257 293
258 /** 294 /**
259 * Get the last key in the map. Returns [null] if the map is empty. 295 * Get the last key in the map. Returns [null] if the map is empty.
260 */ 296 */
261 K lastKey() { 297 K lastKey() {
262 if (_root == null) return null; 298 if (_root == null) return null;
263 SplayTreeNode<K, V> node = _root; 299 SplayTreeNode<K, V> node = _root;
264 while (node.right != null) { 300 while (node.right != null) {
265 node = node.right; 301 node = node.right;
266 } 302 }
267 // Maybe implement a splay-method that can splay the maximum without 303 // Maybe implement a splay-method that can splay the maximum without
268 // performing comparisons. 304 // performing comparisons.
269 splay_(node.key); 305 _splay(node.key);
270 return node.key; 306 return node.key;
271 } 307 }
272 308
273 /** 309 /**
274 * Get the last key in the map that is strictly smaller than [key]. Returns 310 * Get the last key in the map that is strictly smaller than [key]. Returns
275 * [null] if no key was not found. 311 * [null] if no key was not found.
276 */ 312 */
277 K lastKeyBefore(K key) { 313 K lastKeyBefore(K key) {
278 splay_(key); 314 if (_root == null) return null;
279 K visit(SplayTreeNode node, K ifEmpty) { 315 int comp = _splay(key);
280 if (node == null) return ifEmpty; 316 if (comp < 0) return _root.key;
281 if (node.key.compareTo(key) >= 0) { 317 SplayTreeNode<K, V> node = _root.left;
282 return visit(node.left, ifEmpty); 318 if (node == null) return null;
283 } 319 while (node.right != null) {
284 if (node.key.compareTo(key) < 0) { 320 node = node.right;
285 return visit(node.right, node.key);
286 }
287 } 321 }
288 return visit(_root, null); 322 return node.key;
289 } 323 }
290 324
291 /** 325 /**
292 * Get the first key in the map that is strictly larger than [key]. Returns 326 * Get the first key in the map that is strictly larger than [key]. Returns
293 * [null] if no key was not found. 327 * [null] if no key was not found.
294 */ 328 */
295 K firstKeyAfter(K key) { 329 K firstKeyAfter(K key) {
296 splay_(key); 330 if (_root == null) return null;
297 K visit(SplayTreeNode node, K ifEmpty) { 331 int comp = _splay(key);
298 if (node == null) return ifEmpty; 332 if (comp > 0) return _root.key;
299 if (node.key.compareTo(key) > 0) { 333 SplayTreeNode<K, V> node = _root.right;
300 return visit(node.left, node.key); 334 if (node == null) return null;
301 } 335 while (node.left != null) {
302 if (node.key.compareTo(key) <= 0) { 336 node = node.left;
303 return visit(node.right, ifEmpty);
304 }
305 } 337 }
306 return visit(_root, null); 338 return node.key;
307 } 339 }
308 } 340 }
341
342 abstract class _SplayTreeIterator<T> implements Iterator<T> {
343 final SplayTreeMap _map;
344 /**
345 * Worklist of nodes to visit.
346 *
347 * These nodes have been passed over on the way down in a
348 * depth-first left-to-right traversal. Visiting each node,
349 * and their right subtrees will visit the remainder of
350 * the nodes of a full traversal.
351 *
352 * Only valid as long as the original tree map isn't reordered.
353 */
354 final List<SplayTreeNode> _workList = <SplayTreeNode>[];
355
356 /**
357 * Original modification counter of [_map].
358 *
359 * Incremented on [_map] when a key is added or removed.
360 * If it changes, iteration is aborted.
361 */
362 final int _modificationCount;
363 /**
364 * Count of splay operations on [_map] when [_path] was build.
365 *
366 * If the splay count on [_map] increases, [_path] becomes invalid.
floitsch 2013/02/15 10:04:49 _workList
Lasse Reichstein Nielsen 2013/02/15 13:46:37 Done.
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