rbtree-ruby 0.1.5 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +32 -0
- data/README.md +71 -10
- data/lib/rbtree/version.rb +1 -1
- data/lib/rbtree.rb +451 -46
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8aa1d883925f6b7f608108f1f916598aa04be013aee415c06dfc7bda35d6986c
|
|
4
|
+
data.tar.gz: e935f213100c933b42a3cf0d709809d5ca8d536db56d6e27a6b3de9681847ad9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 419f0270137b6a6ae39bd73d5ea0c4cc25ff0769c288619ee795d172e724040c6032c09c952745b9bb871ff082861c00ae879fa6a98a571414bad87c2534cb9a
|
|
7
|
+
data.tar.gz: e403cc18d16ff9661a341fb326b3aadebc5d1a83b69ed03395b318cf6666d8de9dca24e88da2a9c231395aa7780ce57ed89902717ad1266bd1551e384872719f
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,36 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.1.7] - 2026-01-14
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **Predecessor/Successor Search**: New `prev(key)` and `succ(key)` methods
|
|
12
|
+
- Returns the key-value pair immediately before/after the given key
|
|
13
|
+
- Works even if the key doesn't exist in the tree (returns nearest neighbor)
|
|
14
|
+
- Uses hash index for O(1) existence check, then O(log n) tree traversal
|
|
15
|
+
- **Reverse Range Queries**: All range query methods now support `:reverse` option
|
|
16
|
+
- `lt(key, reverse: true)`, `lte`, `gt`, `gte`, `between`
|
|
17
|
+
- Returns results in descending order instead of ascending
|
|
18
|
+
- **MultiRBTree Enhancements**:
|
|
19
|
+
- `get(key, last: false)` - Choose first or last value from array
|
|
20
|
+
- `get_first(key)`, `get_last(key)` - Convenient aliases
|
|
21
|
+
- `delete_one(key, last: false)` - Choose which end to delete from
|
|
22
|
+
- `delete_first(key)`, `delete_last(key)` - Convenient aliases
|
|
23
|
+
- `min(last: false)`, `max(last: false)` - Choose first or last value
|
|
24
|
+
- `prev(key, last: false)`, `succ(key, last: false)` - Choose first or last value
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
- **MultiRBTree Iteration**: Reverse iteration (`reverse_each`, `lt(..., reverse: true)`, etc.) now iterates each key's value array in reverse order (last to first), making it a true mirror of forward iteration
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
- **MultiRBTree size tracking**: Fixed bug where `insert` did not increment size when key already existed in hash index
|
|
31
|
+
|
|
32
|
+
## [0.1.6] - 2026-01-13
|
|
33
|
+
|
|
34
|
+
### Changed
|
|
35
|
+
- **Performance**: Standardized on Boolean colors (`true`/`false`) instead of Symbols (`:red`/`:black`) for faster checks.
|
|
36
|
+
- **Optimization**: `insert` operations now check the internal hash index first, allowing O(1) updates for existing keys (RBTree) and O(1) appends (MultiRBTree).
|
|
37
|
+
|
|
8
38
|
## [0.1.5] - 2026-01-13
|
|
9
39
|
|
|
10
40
|
### Changed
|
|
@@ -77,6 +107,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
77
107
|
- ASCII diagrams for tree rotation operations
|
|
78
108
|
- MIT License (Copyright © 2026 Masahito Suzuki)
|
|
79
109
|
|
|
110
|
+
[0.1.7]: https://github.com/firelzrd/rbtree-ruby/releases/tag/v0.1.7
|
|
111
|
+
[0.1.6]: https://github.com/firelzrd/rbtree-ruby/releases/tag/v0.1.6
|
|
80
112
|
[0.1.5]: https://github.com/firelzrd/rbtree-ruby/releases/tag/v0.1.5
|
|
81
113
|
[0.1.4]: https://github.com/firelzrd/rbtree-ruby/releases/tag/v0.1.4
|
|
82
114
|
[0.1.3]: https://github.com/firelzrd/rbtree-ruby/releases/tag/v0.1.3
|
data/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# rbtree-ruby
|
|
2
2
|
|
|
3
3
|
A pure Ruby implementation of the Red-Black Tree data structure, providing efficient ordered key-value storage with O(log n) time complexity for insertion, deletion, and lookup operations.
|
|
4
4
|
|
|
@@ -127,6 +127,66 @@ tree.nearest(7) # => [5, "five"] (same distance, returns smaller key)
|
|
|
127
127
|
tree.nearest(8) # => [10, "ten"]
|
|
128
128
|
```
|
|
129
129
|
|
|
130
|
+
### Predecessor/Successor Search
|
|
131
|
+
|
|
132
|
+
Find the next or previous key in the tree:
|
|
133
|
+
|
|
134
|
+
```ruby
|
|
135
|
+
tree = RBTree.new({1 => 'one', 3 => 'three', 5 => 'five', 7 => 'seven'})
|
|
136
|
+
|
|
137
|
+
tree.prev(5) # => [3, "three"] (largest key < 5)
|
|
138
|
+
tree.succ(5) # => [7, "seven"] (smallest key > 5)
|
|
139
|
+
|
|
140
|
+
# Works even if the key doesn't exist
|
|
141
|
+
tree.prev(4) # => [3, "three"] (4 doesn't exist, returns largest key < 4)
|
|
142
|
+
tree.succ(4) # => [5, "five"] (4 doesn't exist, returns smallest key > 4)
|
|
143
|
+
|
|
144
|
+
# Returns nil at boundaries
|
|
145
|
+
tree.prev(1) # => nil (no key smaller than 1)
|
|
146
|
+
tree.succ(7) # => nil (no key larger than 7)
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Reverse Range Queries
|
|
150
|
+
|
|
151
|
+
All range queries support a `:reverse` option to iterate in descending order:
|
|
152
|
+
|
|
153
|
+
```ruby
|
|
154
|
+
tree = RBTree.new({1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four'})
|
|
155
|
+
|
|
156
|
+
tree.lt(3) # => [[1, "one"], [2, "two"]]
|
|
157
|
+
tree.lt(3, reverse: true) # => [[2, "two"], [1, "one"]]
|
|
158
|
+
|
|
159
|
+
tree.between(1, 4, reverse: true) # => [[4, "four"], [3, "three"], [2, "two"], [1, "one"]]
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### MultiRBTree Value Array Access
|
|
163
|
+
|
|
164
|
+
For keys with multiple values, choose which value to access:
|
|
165
|
+
|
|
166
|
+
```ruby
|
|
167
|
+
tree = MultiRBTree.new
|
|
168
|
+
tree.insert(1, 'first')
|
|
169
|
+
tree.insert(1, 'second')
|
|
170
|
+
tree.insert(1, 'third')
|
|
171
|
+
|
|
172
|
+
# Access first or last value
|
|
173
|
+
tree.get(1) # => "first"
|
|
174
|
+
tree.get(1, last: true) # => "third"
|
|
175
|
+
tree.get_first(1) # => "first"
|
|
176
|
+
tree.get_last(1) # => "third"
|
|
177
|
+
|
|
178
|
+
# Delete from either end
|
|
179
|
+
tree.delete_first(1) # => "first"
|
|
180
|
+
tree.delete_last(1) # => "third"
|
|
181
|
+
tree.get(1) # => "second"
|
|
182
|
+
|
|
183
|
+
# min/max with :last option
|
|
184
|
+
tree.insert(2, 'a')
|
|
185
|
+
tree.insert(2, 'b')
|
|
186
|
+
tree.min # => [1, "second"] (first value of min key)
|
|
187
|
+
tree.max(last: true) # => [2, "b"] (last value of max key)
|
|
188
|
+
```
|
|
189
|
+
|
|
130
190
|
## Performance
|
|
131
191
|
|
|
132
192
|
All major operations run in **O(log n)** time:
|
|
@@ -138,6 +198,7 @@ All major operations run in **O(log n)** time:
|
|
|
138
198
|
- `min` - **O(1)**
|
|
139
199
|
- `max` - O(log n)
|
|
140
200
|
- `shift` / `pop` - O(log n)
|
|
201
|
+
- `prev` / `succ` - O(log n) with O(1) hash check
|
|
141
202
|
|
|
142
203
|
Iteration over all elements takes O(n) time.
|
|
143
204
|
|
|
@@ -147,17 +208,17 @@ RBTree uses an internal **Memory Pool** to recycle node objects.
|
|
|
147
208
|
- Significantly reduces Garbage Collection (GC) pressure during frequent insertions and deletions (e.g., in high-throughput queues).
|
|
148
209
|
- In benchmarks with 100,000 cyclic operations, **GC time was 0.0s** compared to significant pauses without pooling.
|
|
149
210
|
|
|
150
|
-
### RBTree vs Hash vs Array
|
|
211
|
+
### RBTree vs Hash vs Array (Overwhelming Power)
|
|
151
212
|
|
|
152
|
-
RBTree
|
|
213
|
+
For ordered and spatial operations, RBTree is not just faster—it is in a completely different class. The following benchmarks were conducted with **500,000 items**:
|
|
153
214
|
|
|
154
|
-
| Operation | RBTree | Hash | Speedup |
|
|
155
|
-
|
|
156
|
-
|
|
|
157
|
-
| Range
|
|
158
|
-
|
|
|
159
|
-
|
|
|
160
|
-
| Key
|
|
215
|
+
| Operation | RBTree | Hash/Array | Speedup | Why? |
|
|
216
|
+
|-----------|--------|------------|---------|------|
|
|
217
|
+
| **Nearest Key Search** | **O(log n)** | O(n) scan | **~8,600x faster** | Spatial binary search vs full scan |
|
|
218
|
+
| **Range Queries** | **O(log n + k)** | O(n) filter | **~540x faster** | Direct subtree jump vs full scan |
|
|
219
|
+
| **Min Extraction** | **O(log n)** | O(n) search | **~160x faster** | Continuous rebalancing vs full scan |
|
|
220
|
+
| **Sorted Iteration** | **O(n)** | O(n log n) | **FREE** | Always sorted vs explicit `sort` |
|
|
221
|
+
| **Key Lookup** | **O(1)** | O(1) | **Equal** | Optimized Hybrid Hash Index |
|
|
161
222
|
|
|
162
223
|
### When to Use RBTree
|
|
163
224
|
|
data/lib/rbtree/version.rb
CHANGED
data/lib/rbtree.rb
CHANGED
|
@@ -174,6 +174,11 @@ class RBTree
|
|
|
174
174
|
# tree.insert(1, 'uno', overwrite: false) # => nil (no change)
|
|
175
175
|
# tree[2] = 'two' # using alias
|
|
176
176
|
def insert(key, value, overwrite: true)
|
|
177
|
+
if (node = @hash_index[key])
|
|
178
|
+
return nil unless overwrite
|
|
179
|
+
node.value = value
|
|
180
|
+
return true
|
|
181
|
+
end
|
|
177
182
|
y = @nil_node
|
|
178
183
|
x = @root
|
|
179
184
|
while x != @nil_node
|
|
@@ -324,19 +329,28 @@ class RBTree
|
|
|
324
329
|
# Retrieves all key-value pairs with keys less than the specified key.
|
|
325
330
|
#
|
|
326
331
|
# @param key [Object] the upper bound (exclusive)
|
|
332
|
+
# @param reverse [Boolean] if true, iterate in descending order (default: false)
|
|
327
333
|
# @yield [key, value] each matching key-value pair (if block given)
|
|
328
334
|
# @return [Array<Array(Object, Object)>, RBTree] array of [key, value] pairs if no block, self otherwise
|
|
329
335
|
# @example
|
|
330
336
|
# tree = RBTree.new({1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four'})
|
|
331
337
|
# tree.lt(3) # => [[1, "one"], [2, "two"]]
|
|
332
|
-
# tree.lt(3
|
|
333
|
-
def lt(key, &block)
|
|
338
|
+
# tree.lt(3, reverse: true) # => [[2, "two"], [1, "one"]]
|
|
339
|
+
def lt(key, reverse: false, &block)
|
|
334
340
|
if block_given?
|
|
335
|
-
|
|
341
|
+
if reverse
|
|
342
|
+
traverse_lt_desc(@root, key, &block)
|
|
343
|
+
else
|
|
344
|
+
traverse_lt(@root, key, &block)
|
|
345
|
+
end
|
|
336
346
|
self
|
|
337
347
|
else
|
|
338
348
|
res = []
|
|
339
|
-
|
|
349
|
+
if reverse
|
|
350
|
+
traverse_lt_desc(@root, key) { |k, v| res << [k, v] }
|
|
351
|
+
else
|
|
352
|
+
traverse_lt(@root, key) { |k, v| res << [k, v] }
|
|
353
|
+
end
|
|
340
354
|
res
|
|
341
355
|
end
|
|
342
356
|
end
|
|
@@ -344,18 +358,28 @@ class RBTree
|
|
|
344
358
|
# Retrieves all key-value pairs with keys less than or equal to the specified key.
|
|
345
359
|
#
|
|
346
360
|
# @param key [Object] the upper bound (inclusive)
|
|
361
|
+
# @param reverse [Boolean] if true, iterate in descending order (default: false)
|
|
347
362
|
# @yield [key, value] each matching key-value pair (if block given)
|
|
348
363
|
# @return [Array<Array(Object, Object)>, RBTree] array of [key, value] pairs if no block, self otherwise
|
|
349
364
|
# @example
|
|
350
365
|
# tree = RBTree.new({1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four'})
|
|
351
366
|
# tree.lte(3) # => [[1, "one"], [2, "two"], [3, "three"]]
|
|
352
|
-
|
|
367
|
+
# tree.lte(3, reverse: true) # => [[3, "three"], [2, "two"], [1, "one"]]
|
|
368
|
+
def lte(key, reverse: false, &block)
|
|
353
369
|
if block_given?
|
|
354
|
-
|
|
370
|
+
if reverse
|
|
371
|
+
traverse_lte_desc(@root, key, &block)
|
|
372
|
+
else
|
|
373
|
+
traverse_lte(@root, key, &block)
|
|
374
|
+
end
|
|
355
375
|
self
|
|
356
376
|
else
|
|
357
377
|
res = []
|
|
358
|
-
|
|
378
|
+
if reverse
|
|
379
|
+
traverse_lte_desc(@root, key) { |k, v| res << [k, v] }
|
|
380
|
+
else
|
|
381
|
+
traverse_lte(@root, key) { |k, v| res << [k, v] }
|
|
382
|
+
end
|
|
359
383
|
res
|
|
360
384
|
end
|
|
361
385
|
end
|
|
@@ -363,18 +387,28 @@ class RBTree
|
|
|
363
387
|
# Retrieves all key-value pairs with keys greater than the specified key.
|
|
364
388
|
#
|
|
365
389
|
# @param key [Object] the lower bound (exclusive)
|
|
390
|
+
# @param reverse [Boolean] if true, iterate in descending order (default: false)
|
|
366
391
|
# @yield [key, value] each matching key-value pair (if block given)
|
|
367
392
|
# @return [Array<Array(Object, Object)>, RBTree] array of [key, value] pairs if no block, self otherwise
|
|
368
393
|
# @example
|
|
369
394
|
# tree = RBTree.new({1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four'})
|
|
370
395
|
# tree.gt(2) # => [[3, "three"], [4, "four"]]
|
|
371
|
-
|
|
396
|
+
# tree.gt(2, reverse: true) # => [[4, "four"], [3, "three"]]
|
|
397
|
+
def gt(key, reverse: false, &block)
|
|
372
398
|
if block_given?
|
|
373
|
-
|
|
399
|
+
if reverse
|
|
400
|
+
traverse_gt_desc(@root, key, &block)
|
|
401
|
+
else
|
|
402
|
+
traverse_gt(@root, key, &block)
|
|
403
|
+
end
|
|
374
404
|
self
|
|
375
405
|
else
|
|
376
406
|
res = []
|
|
377
|
-
|
|
407
|
+
if reverse
|
|
408
|
+
traverse_gt_desc(@root, key) { |k, v| res << [k, v] }
|
|
409
|
+
else
|
|
410
|
+
traverse_gt(@root, key) { |k, v| res << [k, v] }
|
|
411
|
+
end
|
|
378
412
|
res
|
|
379
413
|
end
|
|
380
414
|
end
|
|
@@ -382,18 +416,28 @@ class RBTree
|
|
|
382
416
|
# Retrieves all key-value pairs with keys greater than or equal to the specified key.
|
|
383
417
|
#
|
|
384
418
|
# @param key [Object] the lower bound (inclusive)
|
|
419
|
+
# @param reverse [Boolean] if true, iterate in descending order (default: false)
|
|
385
420
|
# @yield [key, value] each matching key-value pair (if block given)
|
|
386
421
|
# @return [Array<Array(Object, Object)>, RBTree] array of [key, value] pairs if no block, self otherwise
|
|
387
422
|
# @example
|
|
388
423
|
# tree = RBTree.new({1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four'})
|
|
389
424
|
# tree.gte(2) # => [[2, "two"], [3, "three"], [4, "four"]]
|
|
390
|
-
|
|
425
|
+
# tree.gte(2, reverse: true) # => [[4, "four"], [3, "three"], [2, "two"]]
|
|
426
|
+
def gte(key, reverse: false, &block)
|
|
391
427
|
if block_given?
|
|
392
|
-
|
|
428
|
+
if reverse
|
|
429
|
+
traverse_gte_desc(@root, key, &block)
|
|
430
|
+
else
|
|
431
|
+
traverse_gte(@root, key, &block)
|
|
432
|
+
end
|
|
393
433
|
self
|
|
394
434
|
else
|
|
395
435
|
res = []
|
|
396
|
-
|
|
436
|
+
if reverse
|
|
437
|
+
traverse_gte_desc(@root, key) { |k, v| res << [k, v] }
|
|
438
|
+
else
|
|
439
|
+
traverse_gte(@root, key) { |k, v| res << [k, v] }
|
|
440
|
+
end
|
|
397
441
|
res
|
|
398
442
|
end
|
|
399
443
|
end
|
|
@@ -404,20 +448,29 @@ class RBTree
|
|
|
404
448
|
# @param max [Object] the upper bound
|
|
405
449
|
# @param include_min [Boolean] whether to include the lower bound (default: true)
|
|
406
450
|
# @param include_max [Boolean] whether to include the upper bound (default: true)
|
|
451
|
+
# @param reverse [Boolean] if true, iterate in descending order (default: false)
|
|
407
452
|
# @yield [key, value] each matching key-value pair (if block given)
|
|
408
453
|
# @return [Array<Array(Object, Object)>, RBTree] array of [key, value] pairs if no block, self otherwise
|
|
409
454
|
# @example
|
|
410
455
|
# tree = RBTree.new({1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four', 5 => 'five'})
|
|
411
456
|
# tree.between(2, 4) # => [[2, "two"], [3, "three"], [4, "four"]]
|
|
412
457
|
# tree.between(2, 4, include_min: false) # => [[3, "three"], [4, "four"]]
|
|
413
|
-
# tree.between(2, 4,
|
|
414
|
-
def between(min, max, include_min: true, include_max: true, &block)
|
|
458
|
+
# tree.between(2, 4, reverse: true) # => [[4, "four"], [3, "three"], [2, "two"]]
|
|
459
|
+
def between(min, max, include_min: true, include_max: true, reverse: false, &block)
|
|
415
460
|
if block_given?
|
|
416
|
-
|
|
461
|
+
if reverse
|
|
462
|
+
traverse_between_desc(@root, min, max, include_min, include_max, &block)
|
|
463
|
+
else
|
|
464
|
+
traverse_between(@root, min, max, include_min, include_max, &block)
|
|
465
|
+
end
|
|
417
466
|
self
|
|
418
467
|
else
|
|
419
468
|
res = []
|
|
420
|
-
|
|
469
|
+
if reverse
|
|
470
|
+
traverse_between_desc(@root, min, max, include_min, include_max) { |k, v| res << [k, v] }
|
|
471
|
+
else
|
|
472
|
+
traverse_between(@root, min, max, include_min, include_max) { |k, v| res << [k, v] }
|
|
473
|
+
end
|
|
421
474
|
res
|
|
422
475
|
end
|
|
423
476
|
end
|
|
@@ -440,6 +493,40 @@ class RBTree
|
|
|
440
493
|
n == @nil_node ? nil : [n.key, n.value]
|
|
441
494
|
end
|
|
442
495
|
|
|
496
|
+
# Returns the key-value pair with the largest key that is smaller than the given key.
|
|
497
|
+
#
|
|
498
|
+
# If the key exists in the tree, returns the predecessor (previous element).
|
|
499
|
+
# If the key does not exist, returns the largest key-value pair with key < given key.
|
|
500
|
+
#
|
|
501
|
+
# @param key [Object] the reference key
|
|
502
|
+
# @return [Array(Object, Object), nil] a two-element array [key, value], or nil if no predecessor exists
|
|
503
|
+
# @example
|
|
504
|
+
# tree = RBTree.new({1 => 'one', 3 => 'three', 5 => 'five', 7 => 'seven'})
|
|
505
|
+
# tree.prev(5) # => [3, "three"]
|
|
506
|
+
# tree.prev(4) # => [3, "three"] (4 does not exist)
|
|
507
|
+
# tree.prev(1) # => nil (no predecessor)
|
|
508
|
+
def prev(key)
|
|
509
|
+
n = find_predecessor_node(key)
|
|
510
|
+
n == @nil_node ? nil : [n.key, n.value]
|
|
511
|
+
end
|
|
512
|
+
|
|
513
|
+
# Returns the key-value pair with the smallest key that is larger than the given key.
|
|
514
|
+
#
|
|
515
|
+
# If the key exists in the tree, returns the successor (next element).
|
|
516
|
+
# If the key does not exist, returns the smallest key-value pair with key > given key.
|
|
517
|
+
#
|
|
518
|
+
# @param key [Object] the reference key
|
|
519
|
+
# @return [Array(Object, Object), nil] a two-element array [key, value], or nil if no successor exists
|
|
520
|
+
# @example
|
|
521
|
+
# tree = RBTree.new({1 => 'one', 3 => 'three', 5 => 'five', 7 => 'seven'})
|
|
522
|
+
# tree.succ(5) # => [7, "seven"]
|
|
523
|
+
# tree.succ(4) # => [5, "five"] (4 does not exist)
|
|
524
|
+
# tree.succ(7) # => nil (no successor)
|
|
525
|
+
def succ(key)
|
|
526
|
+
n = find_successor_node(key)
|
|
527
|
+
n == @nil_node ? nil : [n.key, n.value]
|
|
528
|
+
end
|
|
529
|
+
|
|
443
530
|
# Validates the red-black tree properties.
|
|
444
531
|
#
|
|
445
532
|
# Checks that:
|
|
@@ -588,6 +675,98 @@ class RBTree
|
|
|
588
675
|
end
|
|
589
676
|
end
|
|
590
677
|
|
|
678
|
+
# Traverses nodes with keys less than the specified key in descending order.
|
|
679
|
+
#
|
|
680
|
+
# @param node [Node] the current node
|
|
681
|
+
# @param key [Object] the upper bound (exclusive)
|
|
682
|
+
# @yield [key, value] each matching key-value pair in descending order
|
|
683
|
+
# @return [void]
|
|
684
|
+
def traverse_lt_desc(node, key, &block)
|
|
685
|
+
return if node == @nil_node
|
|
686
|
+
|
|
687
|
+
if (node.key <=> key) < 0
|
|
688
|
+
traverse_lt_desc(node.right, key, &block)
|
|
689
|
+
yield node.key, node.value
|
|
690
|
+
end
|
|
691
|
+
traverse_lt_desc(node.left, key, &block)
|
|
692
|
+
end
|
|
693
|
+
|
|
694
|
+
# Traverses nodes with keys less than or equal to the specified key in descending order.
|
|
695
|
+
#
|
|
696
|
+
# @param node [Node] the current node
|
|
697
|
+
# @param key [Object] the upper bound (inclusive)
|
|
698
|
+
# @yield [key, value] each matching key-value pair in descending order
|
|
699
|
+
# @return [void]
|
|
700
|
+
def traverse_lte_desc(node, key, &block)
|
|
701
|
+
return if node == @nil_node
|
|
702
|
+
|
|
703
|
+
if (node.key <=> key) <= 0
|
|
704
|
+
traverse_lte_desc(node.right, key, &block)
|
|
705
|
+
yield node.key, node.value
|
|
706
|
+
end
|
|
707
|
+
traverse_lte_desc(node.left, key, &block)
|
|
708
|
+
end
|
|
709
|
+
|
|
710
|
+
# Traverses nodes with keys greater than the specified key in descending order.
|
|
711
|
+
#
|
|
712
|
+
# @param node [Node] the current node
|
|
713
|
+
# @param key [Object] the lower bound (exclusive)
|
|
714
|
+
# @yield [key, value] each matching key-value pair in descending order
|
|
715
|
+
# @return [void]
|
|
716
|
+
def traverse_gt_desc(node, key, &block)
|
|
717
|
+
return if node == @nil_node
|
|
718
|
+
|
|
719
|
+
traverse_gt_desc(node.right, key, &block)
|
|
720
|
+
if (node.key <=> key) > 0
|
|
721
|
+
yield node.key, node.value
|
|
722
|
+
traverse_gt_desc(node.left, key, &block)
|
|
723
|
+
end
|
|
724
|
+
end
|
|
725
|
+
|
|
726
|
+
# Traverses nodes with keys greater than or equal to the specified key in descending order.
|
|
727
|
+
#
|
|
728
|
+
# @param node [Node] the current node
|
|
729
|
+
# @param key [Object] the lower bound (inclusive)
|
|
730
|
+
# @yield [key, value] each matching key-value pair in descending order
|
|
731
|
+
# @return [void]
|
|
732
|
+
def traverse_gte_desc(node, key, &block)
|
|
733
|
+
return if node == @nil_node
|
|
734
|
+
|
|
735
|
+
traverse_gte_desc(node.right, key, &block)
|
|
736
|
+
if (node.key <=> key) >= 0
|
|
737
|
+
yield node.key, node.value
|
|
738
|
+
traverse_gte_desc(node.left, key, &block)
|
|
739
|
+
end
|
|
740
|
+
end
|
|
741
|
+
|
|
742
|
+
# Traverses nodes with keys within the specified range in descending order.
|
|
743
|
+
#
|
|
744
|
+
# @param node [Node] the current node
|
|
745
|
+
# @param min [Object] the lower bound
|
|
746
|
+
# @param max [Object] the upper bound
|
|
747
|
+
# @param include_min [Boolean] whether to include the lower bound
|
|
748
|
+
# @param include_max [Boolean] whether to include the upper bound
|
|
749
|
+
# @yield [key, value] each matching key-value pair in descending order
|
|
750
|
+
# @return [void]
|
|
751
|
+
def traverse_between_desc(node, min, max, include_min, include_max, &block)
|
|
752
|
+
return if node == @nil_node
|
|
753
|
+
|
|
754
|
+
if (node.key <=> max) < 0
|
|
755
|
+
traverse_between_desc(node.right, min, max, include_min, include_max, &block)
|
|
756
|
+
end
|
|
757
|
+
|
|
758
|
+
greater = include_min ? (node.key <=> min) >= 0 : (node.key <=> min) > 0
|
|
759
|
+
less = include_max ? (node.key <=> max) <= 0 : (node.key <=> max) < 0
|
|
760
|
+
|
|
761
|
+
if greater && less
|
|
762
|
+
yield node.key, node.value
|
|
763
|
+
end
|
|
764
|
+
|
|
765
|
+
if (node.key <=> min) > 0
|
|
766
|
+
traverse_between_desc(node.left, min, max, include_min, include_max, &block)
|
|
767
|
+
end
|
|
768
|
+
end
|
|
769
|
+
|
|
591
770
|
# Restores red-black tree properties after insertion.
|
|
592
771
|
#
|
|
593
772
|
# This method fixes any violations of red-black properties that may occur
|
|
@@ -837,6 +1016,86 @@ class RBTree
|
|
|
837
1016
|
closest
|
|
838
1017
|
end
|
|
839
1018
|
|
|
1019
|
+
# Finds the node with the largest key that is smaller than the given key.
|
|
1020
|
+
#
|
|
1021
|
+
# If the key exists in the tree, returns its predecessor node.
|
|
1022
|
+
# If the key does not exist, returns the largest node with key < given key.
|
|
1023
|
+
#
|
|
1024
|
+
# @param key [Object] the reference key
|
|
1025
|
+
# @return [Node] the predecessor node, or @nil_node if none exists
|
|
1026
|
+
def find_predecessor_node(key)
|
|
1027
|
+
# Check if key exists using O(1) hash lookup
|
|
1028
|
+
if (node = @hash_index[key])
|
|
1029
|
+
# Key exists: find predecessor in subtree or ancestors
|
|
1030
|
+
if node.left != @nil_node
|
|
1031
|
+
return rightmost(node.left)
|
|
1032
|
+
else
|
|
1033
|
+
# Walk up to find first ancestor where we came from the right
|
|
1034
|
+
current = node
|
|
1035
|
+
parent = current.parent
|
|
1036
|
+
while parent != @nil_node && current == parent.left
|
|
1037
|
+
current = parent
|
|
1038
|
+
parent = parent.parent
|
|
1039
|
+
end
|
|
1040
|
+
return parent
|
|
1041
|
+
end
|
|
1042
|
+
end
|
|
1043
|
+
|
|
1044
|
+
# Key doesn't exist: descend tree tracking the best candidate
|
|
1045
|
+
current = @root
|
|
1046
|
+
predecessor = @nil_node
|
|
1047
|
+
while current != @nil_node
|
|
1048
|
+
cmp = key <=> current.key
|
|
1049
|
+
if cmp > 0
|
|
1050
|
+
predecessor = current # This node's key < given key
|
|
1051
|
+
current = current.right
|
|
1052
|
+
else
|
|
1053
|
+
current = current.left
|
|
1054
|
+
end
|
|
1055
|
+
end
|
|
1056
|
+
predecessor
|
|
1057
|
+
end
|
|
1058
|
+
|
|
1059
|
+
# Finds the node with the smallest key that is larger than the given key.
|
|
1060
|
+
#
|
|
1061
|
+
# If the key exists in the tree, returns its successor node.
|
|
1062
|
+
# If the key does not exist, returns the smallest node with key > given key.
|
|
1063
|
+
#
|
|
1064
|
+
# @param key [Object] the reference key
|
|
1065
|
+
# @return [Node] the successor node, or @nil_node if none exists
|
|
1066
|
+
def find_successor_node(key)
|
|
1067
|
+
# Check if key exists using O(1) hash lookup
|
|
1068
|
+
if (node = @hash_index[key])
|
|
1069
|
+
# Key exists: find successor in subtree or ancestors
|
|
1070
|
+
if node.right != @nil_node
|
|
1071
|
+
return leftmost(node.right)
|
|
1072
|
+
else
|
|
1073
|
+
# Walk up to find first ancestor where we came from the left
|
|
1074
|
+
current = node
|
|
1075
|
+
parent = current.parent
|
|
1076
|
+
while parent != @nil_node && current == parent.right
|
|
1077
|
+
current = parent
|
|
1078
|
+
parent = parent.parent
|
|
1079
|
+
end
|
|
1080
|
+
return parent
|
|
1081
|
+
end
|
|
1082
|
+
end
|
|
1083
|
+
|
|
1084
|
+
# Key doesn't exist: descend tree tracking the best candidate
|
|
1085
|
+
current = @root
|
|
1086
|
+
successor = @nil_node
|
|
1087
|
+
while current != @nil_node
|
|
1088
|
+
cmp = key <=> current.key
|
|
1089
|
+
if cmp < 0
|
|
1090
|
+
successor = current # This node's key > given key
|
|
1091
|
+
current = current.left
|
|
1092
|
+
else
|
|
1093
|
+
current = current.right
|
|
1094
|
+
end
|
|
1095
|
+
end
|
|
1096
|
+
successor
|
|
1097
|
+
end
|
|
1098
|
+
|
|
840
1099
|
# Finds the leftmost (minimum) node in a subtree.
|
|
841
1100
|
#
|
|
842
1101
|
# @param node [Node] the root of the subtree
|
|
@@ -989,7 +1248,39 @@ end
|
|
|
989
1248
|
# * Multiple values per key using arrays
|
|
990
1249
|
# * Separate methods for single deletion (`delete_one`) vs. all deletions (`delete`)
|
|
991
1250
|
# * Values for each key maintain insertion order
|
|
992
|
-
# *
|
|
1251
|
+
# * Configurable access to first or last value via `:last` option
|
|
1252
|
+
#
|
|
1253
|
+
# == Value Array Access
|
|
1254
|
+
#
|
|
1255
|
+
# For each key, values are stored in insertion order. Methods that access
|
|
1256
|
+
# a single value support a `:last` option to choose which end of the array:
|
|
1257
|
+
#
|
|
1258
|
+
# * +get(key)+, +get_first(key)+ - returns first value (oldest)
|
|
1259
|
+
# * +get(key, last: true)+, +get_last(key)+ - returns last value (newest)
|
|
1260
|
+
# * +delete_one(key)+, +delete_first(key)+ - removes first value
|
|
1261
|
+
# * +delete_one(key, last: true)+, +delete_last(key)+ - removes last value
|
|
1262
|
+
# * +prev(key)+, +succ(key)+ - returns first value of adjacent key
|
|
1263
|
+
# * +prev(key, last: true)+, +succ(key, last: true)+ - returns last value
|
|
1264
|
+
#
|
|
1265
|
+
# == Boundary Operations
|
|
1266
|
+
#
|
|
1267
|
+
# * +min+, +max+ - return [key, first_value] by default
|
|
1268
|
+
# * +min(last: true)+, +max(last: true)+ - return [key, last_value]
|
|
1269
|
+
# * +shift+ - removes and returns [smallest_key, first_value]
|
|
1270
|
+
# * +pop+ - removes and returns [largest_key, last_value]
|
|
1271
|
+
#
|
|
1272
|
+
# == Iteration Order
|
|
1273
|
+
#
|
|
1274
|
+
# When iterating over values, the order depends on the direction:
|
|
1275
|
+
#
|
|
1276
|
+
# * Forward iteration (+each+, +lt+, +gt+, etc.): Each key's values are
|
|
1277
|
+
# yielded in insertion order (first to last).
|
|
1278
|
+
#
|
|
1279
|
+
# * Reverse iteration (+reverse_each+, +lt(key, reverse: true)+, etc.):
|
|
1280
|
+
# Each key's values are yielded in reverse insertion order (last to first).
|
|
1281
|
+
#
|
|
1282
|
+
# This ensures consistent behavior where reverse iteration is truly the
|
|
1283
|
+
# mirror image of forward iteration.
|
|
993
1284
|
#
|
|
994
1285
|
# == Usage
|
|
995
1286
|
#
|
|
@@ -998,32 +1289,55 @@ end
|
|
|
998
1289
|
# tree.insert(1, 'second one')
|
|
999
1290
|
# tree.insert(2, 'two')
|
|
1000
1291
|
#
|
|
1001
|
-
# tree.size
|
|
1002
|
-
# tree.get(1)
|
|
1003
|
-
# tree.
|
|
1292
|
+
# tree.size # => 3 (total key-value pairs)
|
|
1293
|
+
# tree.get(1) # => "first one" (first value)
|
|
1294
|
+
# tree.get(1, last: true) # => "second one" (last value)
|
|
1295
|
+
# tree.get_all(1) # => ["first one", "second one"] (all values)
|
|
1004
1296
|
#
|
|
1005
|
-
# tree.delete_one(1)
|
|
1006
|
-
# tree.get(1)
|
|
1297
|
+
# tree.delete_one(1) # removes only "first one"
|
|
1298
|
+
# tree.get(1) # => "second one"
|
|
1007
1299
|
#
|
|
1008
|
-
# tree.delete(1)
|
|
1300
|
+
# tree.delete(1) # removes all remaining values for key 1
|
|
1009
1301
|
#
|
|
1010
1302
|
# @author Masahito Suzuki
|
|
1011
1303
|
# @since 0.1.2
|
|
1012
1304
|
class MultiRBTree < RBTree
|
|
1013
|
-
# Retrieves
|
|
1305
|
+
# Retrieves a value associated with the given key.
|
|
1014
1306
|
#
|
|
1015
1307
|
# @param key [Object] the key to look up
|
|
1016
|
-
# @
|
|
1308
|
+
# @param last [Boolean] if true, return the last value; otherwise return the first (default: false)
|
|
1309
|
+
# @return [Object, nil] the value for the key, or nil if not found
|
|
1017
1310
|
# @example
|
|
1018
1311
|
# tree = MultiRBTree.new
|
|
1019
1312
|
# tree.insert(1, 'first')
|
|
1020
1313
|
# tree.insert(1, 'second')
|
|
1021
|
-
# tree.get(1)
|
|
1022
|
-
|
|
1314
|
+
# tree.get(1) # => "first"
|
|
1315
|
+
# tree.get(1, last: true) # => "second"
|
|
1316
|
+
def get(key, last: false)
|
|
1023
1317
|
n = find_node(key)
|
|
1024
|
-
n == @nil_node || n.value.empty?
|
|
1318
|
+
return nil if n == @nil_node || n.value.empty?
|
|
1319
|
+
last ? n.value.last : n.value.first
|
|
1025
1320
|
end
|
|
1026
|
-
|
|
1321
|
+
|
|
1322
|
+
# Retrieves the first value associated with the given key.
|
|
1323
|
+
#
|
|
1324
|
+
# @param key [Object] the key to look up
|
|
1325
|
+
# @return [Object, nil] the first value for the key, or nil if not found
|
|
1326
|
+
def get_first(key) = get(key, last: false)
|
|
1327
|
+
|
|
1328
|
+
# Retrieves the last value associated with the given key.
|
|
1329
|
+
#
|
|
1330
|
+
# @param key [Object] the key to look up
|
|
1331
|
+
# @return [Object, nil] the last value for the key, or nil if not found
|
|
1332
|
+
def get_last(key) = get(key, last: true)
|
|
1333
|
+
|
|
1334
|
+
# Returns the first value for the given key (for Hash-like access).
|
|
1335
|
+
#
|
|
1336
|
+
# Note: Unlike get(), this method does not accept options.
|
|
1337
|
+
#
|
|
1338
|
+
# @param key [Object] the key to look up
|
|
1339
|
+
# @return [Object, nil] the first value for the key, or nil if not found
|
|
1340
|
+
def [](key) = get(key)
|
|
1027
1341
|
|
|
1028
1342
|
# Retrieves all values associated with the given key.
|
|
1029
1343
|
#
|
|
@@ -1052,6 +1366,11 @@ class MultiRBTree < RBTree
|
|
|
1052
1366
|
# tree.insert(1, 'first')
|
|
1053
1367
|
# tree.insert(1, 'second') # adds another value for key 1
|
|
1054
1368
|
def insert(key, value)
|
|
1369
|
+
if (node = @hash_index[key])
|
|
1370
|
+
node.value << value
|
|
1371
|
+
@size += 1
|
|
1372
|
+
return true
|
|
1373
|
+
end
|
|
1055
1374
|
y = @nil_node
|
|
1056
1375
|
x = @root
|
|
1057
1376
|
while x != @nil_node
|
|
@@ -1090,24 +1409,25 @@ class MultiRBTree < RBTree
|
|
|
1090
1409
|
true
|
|
1091
1410
|
end
|
|
1092
1411
|
|
|
1093
|
-
# Deletes
|
|
1412
|
+
# Deletes a single value for the specified key.
|
|
1094
1413
|
#
|
|
1095
|
-
# If the key has multiple values, removes only
|
|
1414
|
+
# If the key has multiple values, removes only one value.
|
|
1096
1415
|
# If this was the last value for the key, the node is removed from the tree.
|
|
1097
1416
|
#
|
|
1098
1417
|
# @param key [Object] the key to delete from
|
|
1418
|
+
# @param last [Boolean] if true, remove the last value; otherwise remove the first (default: false)
|
|
1099
1419
|
# @return [Object, nil] the deleted value, or nil if key not found
|
|
1100
1420
|
# @example
|
|
1101
1421
|
# tree = MultiRBTree.new
|
|
1102
1422
|
# tree.insert(1, 'first')
|
|
1103
1423
|
# tree.insert(1, 'second')
|
|
1104
|
-
# tree.delete_one(1)
|
|
1105
|
-
# tree.
|
|
1106
|
-
def delete_one(key)
|
|
1424
|
+
# tree.delete_one(1) # => "first"
|
|
1425
|
+
# tree.delete_one(1, last: true) # => "second" (if more values existed)
|
|
1426
|
+
def delete_one(key, last: false)
|
|
1107
1427
|
z = @hash_index[key] # O(1) lookup
|
|
1108
1428
|
return nil unless z
|
|
1109
1429
|
|
|
1110
|
-
value = z.value.shift
|
|
1430
|
+
value = last ? z.value.pop : z.value.shift
|
|
1111
1431
|
@size -= 1
|
|
1112
1432
|
if z.value.empty?
|
|
1113
1433
|
@hash_index.delete(key) # Remove from index when node removed
|
|
@@ -1116,6 +1436,18 @@ class MultiRBTree < RBTree
|
|
|
1116
1436
|
value
|
|
1117
1437
|
end
|
|
1118
1438
|
|
|
1439
|
+
# Deletes the first value for the specified key.
|
|
1440
|
+
#
|
|
1441
|
+
# @param key [Object] the key to delete from
|
|
1442
|
+
# @return [Object, nil] the deleted value, or nil if key not found
|
|
1443
|
+
def delete_first(key) = delete_one(key, last: false)
|
|
1444
|
+
|
|
1445
|
+
# Deletes the last value for the specified key.
|
|
1446
|
+
#
|
|
1447
|
+
# @param key [Object] the key to delete from
|
|
1448
|
+
# @return [Object, nil] the deleted value, or nil if key not found
|
|
1449
|
+
def delete_last(key) = delete_one(key, last: true)
|
|
1450
|
+
|
|
1119
1451
|
# Deletes all values for the specified key.
|
|
1120
1452
|
#
|
|
1121
1453
|
# Removes the node and all associated values.
|
|
@@ -1163,18 +1495,32 @@ class MultiRBTree < RBTree
|
|
|
1163
1495
|
[n.key, val]
|
|
1164
1496
|
end
|
|
1165
1497
|
|
|
1166
|
-
def min
|
|
1498
|
+
def min(last: false)
|
|
1167
1499
|
return nil if @min_node == @nil_node || @min_node.value.empty?
|
|
1168
|
-
[@min_node.key, @min_node.value.first]
|
|
1500
|
+
[@min_node.key, last ? @min_node.value.last : @min_node.value.first]
|
|
1169
1501
|
end
|
|
1170
1502
|
|
|
1171
|
-
def max
|
|
1503
|
+
def max(last: false)
|
|
1172
1504
|
n = rightmost(@root)
|
|
1173
|
-
n == @nil_node || n.value.empty?
|
|
1505
|
+
return nil if n == @nil_node || n.value.empty?
|
|
1506
|
+
[n.key, last ? n.value.last : n.value.first]
|
|
1174
1507
|
end
|
|
1175
1508
|
|
|
1176
1509
|
def nearest(key)
|
|
1177
|
-
|
|
1510
|
+
n = find_nearest_node(key)
|
|
1511
|
+
n == @nil_node || n.value.empty? ? nil : [n.key, n.value.first]
|
|
1512
|
+
end
|
|
1513
|
+
|
|
1514
|
+
def prev(key, last: false)
|
|
1515
|
+
n = find_predecessor_node(key)
|
|
1516
|
+
return nil if n == @nil_node || n.value.empty?
|
|
1517
|
+
[n.key, last ? n.value.last : n.value.first]
|
|
1518
|
+
end
|
|
1519
|
+
|
|
1520
|
+
def succ(key, last: false)
|
|
1521
|
+
n = find_successor_node(key)
|
|
1522
|
+
return nil if n == @nil_node || n.value.empty?
|
|
1523
|
+
[n.key, last ? n.value.last : n.value.first]
|
|
1178
1524
|
end
|
|
1179
1525
|
|
|
1180
1526
|
private
|
|
@@ -1264,6 +1610,65 @@ class MultiRBTree < RBTree
|
|
|
1264
1610
|
traverse_between(node.right, min, max, include_min, include_max, &block)
|
|
1265
1611
|
end
|
|
1266
1612
|
end
|
|
1613
|
+
|
|
1614
|
+
def traverse_lt_desc(node, key, &block)
|
|
1615
|
+
return if node == @nil_node
|
|
1616
|
+
|
|
1617
|
+
if (node.key <=> key) < 0
|
|
1618
|
+
traverse_lt_desc(node.right, key, &block)
|
|
1619
|
+
node.value.reverse_each { |v| yield node.key, v }
|
|
1620
|
+
end
|
|
1621
|
+
traverse_lt_desc(node.left, key, &block)
|
|
1622
|
+
end
|
|
1623
|
+
|
|
1624
|
+
def traverse_lte_desc(node, key, &block)
|
|
1625
|
+
return if node == @nil_node
|
|
1626
|
+
|
|
1627
|
+
if (node.key <=> key) <= 0
|
|
1628
|
+
traverse_lte_desc(node.right, key, &block)
|
|
1629
|
+
node.value.reverse_each { |v| yield node.key, v }
|
|
1630
|
+
end
|
|
1631
|
+
traverse_lte_desc(node.left, key, &block)
|
|
1632
|
+
end
|
|
1633
|
+
|
|
1634
|
+
def traverse_gt_desc(node, key, &block)
|
|
1635
|
+
return if node == @nil_node
|
|
1636
|
+
|
|
1637
|
+
traverse_gt_desc(node.right, key, &block)
|
|
1638
|
+
if (node.key <=> key) > 0
|
|
1639
|
+
node.value.reverse_each { |v| yield node.key, v }
|
|
1640
|
+
traverse_gt_desc(node.left, key, &block)
|
|
1641
|
+
end
|
|
1642
|
+
end
|
|
1643
|
+
|
|
1644
|
+
def traverse_gte_desc(node, key, &block)
|
|
1645
|
+
return if node == @nil_node
|
|
1646
|
+
|
|
1647
|
+
traverse_gte_desc(node.right, key, &block)
|
|
1648
|
+
if (node.key <=> key) >= 0
|
|
1649
|
+
node.value.reverse_each { |v| yield node.key, v }
|
|
1650
|
+
traverse_gte_desc(node.left, key, &block)
|
|
1651
|
+
end
|
|
1652
|
+
end
|
|
1653
|
+
|
|
1654
|
+
def traverse_between_desc(node, min, max, include_min, include_max, &block)
|
|
1655
|
+
return if node == @nil_node
|
|
1656
|
+
|
|
1657
|
+
if (node.key <=> max) < 0
|
|
1658
|
+
traverse_between_desc(node.right, min, max, include_min, include_max, &block)
|
|
1659
|
+
end
|
|
1660
|
+
|
|
1661
|
+
greater = include_min ? (node.key <=> min) >= 0 : (node.key <=> min) > 0
|
|
1662
|
+
less = include_max ? (node.key <=> max) <= 0 : (node.key <=> max) < 0
|
|
1663
|
+
|
|
1664
|
+
if greater && less
|
|
1665
|
+
node.value.reverse_each { |v| yield node.key, v }
|
|
1666
|
+
end
|
|
1667
|
+
|
|
1668
|
+
if (node.key <=> min) > 0
|
|
1669
|
+
traverse_between_desc(node.left, min, max, include_min, include_max, &block)
|
|
1670
|
+
end
|
|
1671
|
+
end
|
|
1267
1672
|
end
|
|
1268
1673
|
|
|
1269
1674
|
# Internal node structure for RBTree.
|
|
@@ -1288,16 +1693,16 @@ end
|
|
|
1288
1693
|
class RBTree::Node
|
|
1289
1694
|
attr_accessor :key, :value, :color, :left, :right, :parent
|
|
1290
1695
|
|
|
1291
|
-
# Red color constant
|
|
1292
|
-
RED =
|
|
1293
|
-
# Black color constant
|
|
1294
|
-
BLACK =
|
|
1696
|
+
# Red color constant (true)
|
|
1697
|
+
RED = true
|
|
1698
|
+
# Black color constant (false)
|
|
1699
|
+
BLACK = false
|
|
1295
1700
|
|
|
1296
1701
|
# Creates a new Node.
|
|
1297
1702
|
#
|
|
1298
1703
|
# @param key [Object] the key
|
|
1299
1704
|
# @param value [Object] the value
|
|
1300
|
-
# @param color [
|
|
1705
|
+
# @param color [Boolean] the color (true=red, false=black)
|
|
1301
1706
|
# @param left [Node] the left child
|
|
1302
1707
|
# @param right [Node] the right child
|
|
1303
1708
|
# @param parent [Node] the parent node
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rbtree-ruby
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.7
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Masahito Suzuki
|
|
@@ -47,7 +47,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
47
47
|
- !ruby/object:Gem::Version
|
|
48
48
|
version: '0'
|
|
49
49
|
requirements: []
|
|
50
|
-
rubygems_version:
|
|
50
|
+
rubygems_version: 4.0.3
|
|
51
51
|
specification_version: 4
|
|
52
52
|
summary: A pure Ruby implementation of Red-Black Tree with multi-value support
|
|
53
53
|
test_files: []
|