rbtree-ruby 0.2.0 → 0.2.1
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 +19 -0
- data/README.ja.md +10 -3
- data/README.md +10 -3
- data/lib/rbtree/version.rb +1 -1
- data/lib/rbtree.rb +268 -57
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 89348dfde7177409ecdca6a4184ebee7f83f3a57eebb84b3f4925ad4460a7a92
|
|
4
|
+
data.tar.gz: bd46b055e05a121787b67ecf20836181800abe0a230800703872c1412826ccfa
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 908a2d3d58bfac4c7d092e745ebe7f3f2c391551ea5fa7822871d1d0334c64985169df7433342e0e77cad9cf85f8a6b1a265ee427d96445095b3aa27da73d8ef
|
|
7
|
+
data.tar.gz: c7b5afe4a5189deee48c6abc5cbca6340c14ebfc65d581f2788117bfb84aabca7757582ab5b6bbcf7cc5866e6350be4f85f87fda78ea49af8c394dd0884de6b3
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,25 @@ 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.2.1] - 2026-01-14
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **Enhanced iteration**: `each` now accepts `reverse:` and `safe:` options
|
|
12
|
+
- `tree.each(reverse: true) { ... }` (same as `reverse_each`)
|
|
13
|
+
- `tree.each(safe: true) { ... }` (modification-safe)
|
|
14
|
+
- `tree.each(reverse: true, safe: true) { ... }` (reverse modification-safe)
|
|
15
|
+
- In `MultiRBTree`, `reverse: true` also iterates over values in reverse insertion order.
|
|
16
|
+
- **Range query safe mode**: `safe:` option for `lt`, `lte`, `gt`, `gte`, `between`
|
|
17
|
+
- `tree.lt(10, safe: true) { |k, _| tree.delete(k) if k.even? }`
|
|
18
|
+
- Works with `:reverse` option: `tree.gt(5, reverse: true, safe: true)`
|
|
19
|
+
- Returns Enumerator: `tree.between(1, 100, safe: true).select { ... }`
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
- **MultiRBTree#get_all**: Now returns an `Enumerator` instead of an `Array` when no block is given.
|
|
23
|
+
- Improves consistency with other iteration methods.
|
|
24
|
+
- Safe handling for non-existent keys (returns empty Enumerator/nil logic handled safely).
|
|
25
|
+
- Use `.to_a` to get an Array: `tree.get_all(key).to_a`
|
|
26
|
+
|
|
8
27
|
## [0.2.0] - 2026-01-14
|
|
9
28
|
|
|
10
29
|
### Added
|
data/README.ja.md
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
🌍 *[English](README.md) | [日本語](README.ja.md)*
|
|
4
4
|
|
|
5
|
-
Red-Black Tree(赤黒木)データ構造のピュアRuby実装です。挿入、削除、検索操作がO(log n)
|
|
5
|
+
Red-Black Tree(赤黒木)データ構造のピュアRuby実装です。挿入、削除、検索操作がO(log n)の時間計算量で実行できる、
|
|
6
|
+
効率的な順序付きキーバリューストレージを提供します。
|
|
6
7
|
|
|
7
8
|
## 特徴
|
|
8
9
|
|
|
@@ -60,6 +61,12 @@ tree.each { |key, value| puts "#{key}: #{value}" }
|
|
|
60
61
|
# 10: ten
|
|
61
62
|
# 20: twenty
|
|
62
63
|
|
|
64
|
+
# イテレーション中の変更
|
|
65
|
+
# 標準のHashやArrayとは異なり、`safe: true`オプションを指定することで
|
|
66
|
+
# イテレーション中に安全にキーの削除や挿入を行うことができます。
|
|
67
|
+
tree.each(safe: true) { |k, v| tree.delete(k) if k.even? }
|
|
68
|
+
tree.each(reverse: true) { |k, v| puts k } # reverse_eachと同じ
|
|
69
|
+
|
|
63
70
|
# 最小値と最大値
|
|
64
71
|
tree.min # => [1, "one"]
|
|
65
72
|
tree.max # => [20, "twenty"]
|
|
@@ -100,8 +107,8 @@ tree.size # => 4 (キーバリューペアの総数)
|
|
|
100
107
|
tree.get(1) # => "first one"
|
|
101
108
|
tree[1] # => "first one"
|
|
102
109
|
|
|
103
|
-
#
|
|
104
|
-
tree.get_all(1) # => ["first one", "second one", "third one"]
|
|
110
|
+
# キーの全ての値を取得(Enumeratorを返す)
|
|
111
|
+
tree.get_all(1).to_a # => ["first one", "second one", "third one"]
|
|
105
112
|
|
|
106
113
|
# 全キーバリューペアをイテレーション
|
|
107
114
|
tree.each { |k, v| puts "#{k}: #{v}" }
|
data/README.md
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
🌍 *[English](README.md) | [日本語](README.ja.md)*
|
|
4
4
|
|
|
5
|
-
A pure Ruby implementation of the Red-Black Tree data structure, providing efficient ordered
|
|
5
|
+
A pure Ruby implementation of the Red-Black Tree data structure, providing efficient ordered
|
|
6
|
+
key-value storage with O(log n) time complexity for insertion, deletion, and lookup operations.
|
|
6
7
|
|
|
7
8
|
## Features
|
|
8
9
|
|
|
@@ -60,6 +61,12 @@ tree.each { |key, value| puts "#{key}: #{value}" }
|
|
|
60
61
|
# 10: ten
|
|
61
62
|
# 20: twenty
|
|
62
63
|
|
|
64
|
+
# Modification during iteration
|
|
65
|
+
# Unlike standard Ruby Hash/Array, modification during iteration is fully supported
|
|
66
|
+
# with the `safe: true` option. This allows you to delete or insert keys safely while iterating.
|
|
67
|
+
tree.each(safe: true) { |k, v| tree.delete(k) if k.even? }
|
|
68
|
+
tree.each(reverse: true) { |k, v| puts k } # Same as reverse_each
|
|
69
|
+
|
|
63
70
|
# Min and max
|
|
64
71
|
tree.min # => [1, "one"]
|
|
65
72
|
tree.max # => [20, "twenty"]
|
|
@@ -100,8 +107,8 @@ tree.size # => 4 (total number of key-value pairs)
|
|
|
100
107
|
tree.get(1) # => "first one"
|
|
101
108
|
tree[1] # => "first one"
|
|
102
109
|
|
|
103
|
-
# Get all values for a key
|
|
104
|
-
tree.get_all(1) # => ["first one", "second one", "third one"]
|
|
110
|
+
# Get all values for a key (returns Enumerator)
|
|
111
|
+
tree.get_all(1).to_a # => ["first one", "second one", "third one"]
|
|
105
112
|
|
|
106
113
|
# Iterate over all key-value pairs
|
|
107
114
|
tree.each { |k, v| puts "#{k}: #{v}" }
|
data/lib/rbtree/version.rb
CHANGED
data/lib/rbtree.rb
CHANGED
|
@@ -268,13 +268,15 @@ class RBTree
|
|
|
268
268
|
def pop
|
|
269
269
|
n = rightmost(@root)
|
|
270
270
|
return nil if n == @nil_node
|
|
271
|
-
result =
|
|
271
|
+
result = n.pair
|
|
272
272
|
delete(n.key)
|
|
273
273
|
result
|
|
274
274
|
end
|
|
275
275
|
|
|
276
|
-
# Iterates over all key-value pairs in ascending
|
|
276
|
+
# Iterates over all key-value pairs in ascending (or descending) order.
|
|
277
277
|
#
|
|
278
|
+
# @param reverse [Boolean] if true, iterate in descending order (default: false)
|
|
279
|
+
# @param safe [Boolean] if true, safe for modifications during iteration (default: false)
|
|
278
280
|
# @yield [key, value] each key-value pair in the tree
|
|
279
281
|
# @return [Enumerator, RBTree] an Enumerator if no block is given, self otherwise
|
|
280
282
|
# @example
|
|
@@ -284,9 +286,40 @@ class RBTree
|
|
|
284
286
|
# # 1: one
|
|
285
287
|
# # 2: two
|
|
286
288
|
# # 3: three
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
289
|
+
#
|
|
290
|
+
# # Reverse iteration
|
|
291
|
+
# tree.each(reverse: true) { |k, v| ... }
|
|
292
|
+
#
|
|
293
|
+
# # Safe iteration for modifications
|
|
294
|
+
# tree.each(safe: true) do |k, v|
|
|
295
|
+
# tree.delete(k) if k.even?
|
|
296
|
+
# end
|
|
297
|
+
def each(reverse: false, safe: false, &block)
|
|
298
|
+
return enum_for(:each, reverse: reverse, safe: safe) unless block_given?
|
|
299
|
+
if safe
|
|
300
|
+
if reverse
|
|
301
|
+
pair = find_max
|
|
302
|
+
while pair
|
|
303
|
+
current_key = pair[0]
|
|
304
|
+
yield pair[0], pair[1]
|
|
305
|
+
pair = find_predecessor(current_key)
|
|
306
|
+
end
|
|
307
|
+
else
|
|
308
|
+
pair = find_min
|
|
309
|
+
while pair
|
|
310
|
+
current_key = pair[0]
|
|
311
|
+
yield pair[0], pair[1]
|
|
312
|
+
pair = find_successor(current_key)
|
|
313
|
+
end
|
|
314
|
+
end
|
|
315
|
+
else
|
|
316
|
+
if reverse
|
|
317
|
+
traverse_desc(@root, &block)
|
|
318
|
+
else
|
|
319
|
+
traverse_asc(@root, &block)
|
|
320
|
+
end
|
|
321
|
+
end
|
|
322
|
+
self
|
|
290
323
|
end
|
|
291
324
|
|
|
292
325
|
# Iterates over all key-value pairs in descending order of keys.
|
|
@@ -300,10 +333,15 @@ class RBTree
|
|
|
300
333
|
# # 3: three
|
|
301
334
|
# # 2: two
|
|
302
335
|
# # 1: one
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
336
|
+
# Iterates over all key-value pairs in descending order of keys.
|
|
337
|
+
#
|
|
338
|
+
# This is an alias for `each(reverse: true)`.
|
|
339
|
+
#
|
|
340
|
+
# @param safe [Boolean] if true, safe for modifications during iteration (default: false)
|
|
341
|
+
# @yield [key, value] each key-value pair in the tree
|
|
342
|
+
# @return [Enumerator, RBTree] an Enumerator if no block is given, self otherwise
|
|
343
|
+
# @see #each
|
|
344
|
+
def reverse_each(safe: false, &block) = each(reverse: true, safe: safe, &block)
|
|
307
345
|
|
|
308
346
|
# Returns the minimum key-value pair without removing it.
|
|
309
347
|
#
|
|
@@ -311,9 +349,7 @@ class RBTree
|
|
|
311
349
|
# @example
|
|
312
350
|
# tree = RBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
|
|
313
351
|
# tree.min # => [1, "one"]
|
|
314
|
-
def min
|
|
315
|
-
@min_node == @nil_node ? nil : [@min_node.key, @min_node.value]
|
|
316
|
-
end
|
|
352
|
+
def min = find_min
|
|
317
353
|
|
|
318
354
|
# Returns the maximum key-value pair without removing it.
|
|
319
355
|
#
|
|
@@ -321,25 +357,39 @@ class RBTree
|
|
|
321
357
|
# @example
|
|
322
358
|
# tree = RBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
|
|
323
359
|
# tree.max # => [3, "three"]
|
|
324
|
-
def max
|
|
325
|
-
n = rightmost(@root)
|
|
326
|
-
n == @nil_node ? nil : [n.key, n.value]
|
|
327
|
-
end
|
|
360
|
+
def max = find_max
|
|
328
361
|
|
|
329
362
|
# Retrieves all key-value pairs with keys less than the specified key.
|
|
330
363
|
#
|
|
331
364
|
# @param key [Object] the upper bound (exclusive)
|
|
332
365
|
# @param reverse [Boolean] if true, iterate in descending order (default: false)
|
|
366
|
+
# @param safe [Boolean] if true, safe for modifications during iteration (default: false)
|
|
333
367
|
# @yield [key, value] each matching key-value pair (if block given)
|
|
334
368
|
# @return [Enumerator, RBTree] Enumerator if no block given, self otherwise
|
|
335
369
|
# @example
|
|
336
370
|
# tree = RBTree.new({1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four'})
|
|
337
371
|
# tree.lt(3).to_a # => [[1, "one"], [2, "two"]]
|
|
338
372
|
# tree.lt(3, reverse: true).first # => [2, "two"]
|
|
339
|
-
# tree.lt(3) { |k,
|
|
340
|
-
def lt(key, reverse: false, &block)
|
|
341
|
-
return enum_for(:lt, key, reverse: reverse) unless block_given?
|
|
342
|
-
if
|
|
373
|
+
# tree.lt(3, safe: true) { |k, _| tree.delete(k) if k.even? } # safe to delete
|
|
374
|
+
def lt(key, reverse: false, safe: false, &block)
|
|
375
|
+
return enum_for(:lt, key, reverse: reverse, safe: safe) unless block_given?
|
|
376
|
+
if safe
|
|
377
|
+
if reverse
|
|
378
|
+
pair = find_predecessor(key)
|
|
379
|
+
while pair
|
|
380
|
+
current_key = pair[0]
|
|
381
|
+
yield pair
|
|
382
|
+
pair = find_predecessor(current_key)
|
|
383
|
+
end
|
|
384
|
+
else
|
|
385
|
+
pair = find_min
|
|
386
|
+
while pair && pair[0] < key
|
|
387
|
+
current_key = pair[0]
|
|
388
|
+
yield pair
|
|
389
|
+
pair = find_successor(current_key)
|
|
390
|
+
end
|
|
391
|
+
end
|
|
392
|
+
elsif reverse
|
|
343
393
|
traverse_lt_desc(@root, key, &block)
|
|
344
394
|
else
|
|
345
395
|
traverse_lt(@root, key, &block)
|
|
@@ -351,15 +401,32 @@ class RBTree
|
|
|
351
401
|
#
|
|
352
402
|
# @param key [Object] the upper bound (inclusive)
|
|
353
403
|
# @param reverse [Boolean] if true, iterate in descending order (default: false)
|
|
404
|
+
# @param safe [Boolean] if true, safe for modifications during iteration (default: false)
|
|
354
405
|
# @yield [key, value] each matching key-value pair (if block given)
|
|
355
406
|
# @return [Enumerator, RBTree] Enumerator if no block given, self otherwise
|
|
356
407
|
# @example
|
|
357
408
|
# tree = RBTree.new({1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four'})
|
|
358
409
|
# tree.lte(3).to_a # => [[1, "one"], [2, "two"], [3, "three"]]
|
|
359
410
|
# tree.lte(3, reverse: true).first # => [3, "three"]
|
|
360
|
-
def lte(key, reverse: false, &block)
|
|
361
|
-
return enum_for(:lte, key, reverse: reverse) unless block_given?
|
|
362
|
-
if
|
|
411
|
+
def lte(key, reverse: false, safe: false, &block)
|
|
412
|
+
return enum_for(:lte, key, reverse: reverse, safe: safe) unless block_given?
|
|
413
|
+
if safe
|
|
414
|
+
if reverse
|
|
415
|
+
pair = @hash_index[key]&.pair || find_predecessor(key)
|
|
416
|
+
while pair
|
|
417
|
+
current_key = pair[0]
|
|
418
|
+
yield pair
|
|
419
|
+
pair = find_predecessor(current_key)
|
|
420
|
+
end
|
|
421
|
+
else
|
|
422
|
+
pair = find_min
|
|
423
|
+
while pair && pair[0] <= key
|
|
424
|
+
current_key = pair[0]
|
|
425
|
+
yield pair
|
|
426
|
+
pair = succ(current_key)
|
|
427
|
+
end
|
|
428
|
+
end
|
|
429
|
+
elsif reverse
|
|
363
430
|
traverse_lte_desc(@root, key, &block)
|
|
364
431
|
else
|
|
365
432
|
traverse_lte(@root, key, &block)
|
|
@@ -371,15 +438,32 @@ class RBTree
|
|
|
371
438
|
#
|
|
372
439
|
# @param key [Object] the lower bound (exclusive)
|
|
373
440
|
# @param reverse [Boolean] if true, iterate in descending order (default: false)
|
|
441
|
+
# @param safe [Boolean] if true, safe for modifications during iteration (default: false)
|
|
374
442
|
# @yield [key, value] each matching key-value pair (if block given)
|
|
375
443
|
# @return [Enumerator, RBTree] Enumerator if no block given, self otherwise
|
|
376
444
|
# @example
|
|
377
445
|
# tree = RBTree.new({1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four'})
|
|
378
446
|
# tree.gt(2).to_a # => [[3, "three"], [4, "four"]]
|
|
379
447
|
# tree.gt(2, reverse: true).first # => [4, "four"]
|
|
380
|
-
def gt(key, reverse: false, &block)
|
|
381
|
-
return enum_for(:gt, key, reverse: reverse) unless block_given?
|
|
382
|
-
if
|
|
448
|
+
def gt(key, reverse: false, safe: false, &block)
|
|
449
|
+
return enum_for(:gt, key, reverse: reverse, safe: safe) unless block_given?
|
|
450
|
+
if safe
|
|
451
|
+
if reverse
|
|
452
|
+
pair = find_max
|
|
453
|
+
while pair && pair[0] > key
|
|
454
|
+
current_key = pair[0]
|
|
455
|
+
yield pair
|
|
456
|
+
pair = find_predecessor(current_key)
|
|
457
|
+
end
|
|
458
|
+
else
|
|
459
|
+
pair = find_successor(key)
|
|
460
|
+
while pair
|
|
461
|
+
current_key = pair[0]
|
|
462
|
+
yield pair
|
|
463
|
+
pair = find_successor(current_key)
|
|
464
|
+
end
|
|
465
|
+
end
|
|
466
|
+
elsif reverse
|
|
383
467
|
traverse_gt_desc(@root, key, &block)
|
|
384
468
|
else
|
|
385
469
|
traverse_gt(@root, key, &block)
|
|
@@ -391,15 +475,32 @@ class RBTree
|
|
|
391
475
|
#
|
|
392
476
|
# @param key [Object] the lower bound (inclusive)
|
|
393
477
|
# @param reverse [Boolean] if true, iterate in descending order (default: false)
|
|
478
|
+
# @param safe [Boolean] if true, safe for modifications during iteration (default: false)
|
|
394
479
|
# @yield [key, value] each matching key-value pair (if block given)
|
|
395
480
|
# @return [Enumerator, RBTree] Enumerator if no block given, self otherwise
|
|
396
481
|
# @example
|
|
397
482
|
# tree = RBTree.new({1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four'})
|
|
398
483
|
# tree.gte(2).to_a # => [[2, "two"], [3, "three"], [4, "four"]]
|
|
399
484
|
# tree.gte(2, reverse: true).first # => [4, "four"]
|
|
400
|
-
def gte(key, reverse: false, &block)
|
|
401
|
-
return enum_for(:gte, key, reverse: reverse) unless block_given?
|
|
402
|
-
if
|
|
485
|
+
def gte(key, reverse: false, safe: false, &block)
|
|
486
|
+
return enum_for(:gte, key, reverse: reverse, safe: safe) unless block_given?
|
|
487
|
+
if safe
|
|
488
|
+
if reverse
|
|
489
|
+
pair = find_max
|
|
490
|
+
while pair && pair[0] >= key
|
|
491
|
+
current_key = pair[0]
|
|
492
|
+
yield pair
|
|
493
|
+
pair = find_predecessor(current_key)
|
|
494
|
+
end
|
|
495
|
+
else
|
|
496
|
+
pair = @hash_index[key]&.pair || find_successor(key)
|
|
497
|
+
while pair
|
|
498
|
+
current_key = pair[0]
|
|
499
|
+
yield pair
|
|
500
|
+
pair = find_successor(current_key)
|
|
501
|
+
end
|
|
502
|
+
end
|
|
503
|
+
elsif reverse
|
|
403
504
|
traverse_gte_desc(@root, key, &block)
|
|
404
505
|
else
|
|
405
506
|
traverse_gte(@root, key, &block)
|
|
@@ -414,15 +515,34 @@ class RBTree
|
|
|
414
515
|
# @param include_min [Boolean] whether to include the lower bound (default: true)
|
|
415
516
|
# @param include_max [Boolean] whether to include the upper bound (default: true)
|
|
416
517
|
# @param reverse [Boolean] if true, iterate in descending order (default: false)
|
|
518
|
+
# @param safe [Boolean] if true, safe for modifications during iteration (default: false)
|
|
417
519
|
# @yield [key, value] each matching key-value pair (if block given)
|
|
418
520
|
# @return [Enumerator, RBTree] Enumerator if no block given, self otherwise
|
|
419
521
|
# @example
|
|
420
522
|
# tree = RBTree.new({1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four', 5 => 'five'})
|
|
421
523
|
# tree.between(2, 4).to_a # => [[2, "two"], [3, "three"], [4, "four"]]
|
|
422
524
|
# tree.between(2, 4, reverse: true).first # => [4, "four"]
|
|
423
|
-
def between(min, max, include_min: true, include_max: true, reverse: false, &block)
|
|
424
|
-
return enum_for(:between, min, max, include_min: include_min, include_max: include_max, reverse: reverse) unless block_given?
|
|
425
|
-
if
|
|
525
|
+
def between(min, max, include_min: true, include_max: true, reverse: false, safe: false, &block)
|
|
526
|
+
return enum_for(:between, min, max, include_min: include_min, include_max: include_max, reverse: reverse, safe: safe) unless block_given?
|
|
527
|
+
if safe
|
|
528
|
+
if reverse
|
|
529
|
+
pair = include_max && @hash_index[max]&.pair || find_predecessor(max)
|
|
530
|
+
while pair && pair[0] > min
|
|
531
|
+
current_key = pair[0]
|
|
532
|
+
yield pair
|
|
533
|
+
pair = find_predecessor(current_key)
|
|
534
|
+
end
|
|
535
|
+
yield pair if pair && include_min && pair[0] == min
|
|
536
|
+
else
|
|
537
|
+
pair = include_min && @hash_index[min]&.pair || find_successor(min)
|
|
538
|
+
while pair && pair[0] < max
|
|
539
|
+
current_key = pair[0]
|
|
540
|
+
yield pair
|
|
541
|
+
pair = find_successor(current_key)
|
|
542
|
+
end
|
|
543
|
+
yield pair if pair && include_max && pair[0] == max
|
|
544
|
+
end
|
|
545
|
+
elsif reverse
|
|
426
546
|
traverse_between_desc(@root, min, max, include_min, include_max, &block)
|
|
427
547
|
else
|
|
428
548
|
traverse_between(@root, min, max, include_min, include_max, &block)
|
|
@@ -445,7 +565,7 @@ class RBTree
|
|
|
445
565
|
def nearest(key)
|
|
446
566
|
return nil unless key.respond_to?(:-)
|
|
447
567
|
n = find_nearest_node(key)
|
|
448
|
-
n == @nil_node ? nil :
|
|
568
|
+
n == @nil_node ? nil : n.pair
|
|
449
569
|
end
|
|
450
570
|
|
|
451
571
|
# Returns the key-value pair with the largest key that is smaller than the given key.
|
|
@@ -462,7 +582,7 @@ class RBTree
|
|
|
462
582
|
# tree.prev(1) # => nil (no predecessor)
|
|
463
583
|
def prev(key)
|
|
464
584
|
n = find_predecessor_node(key)
|
|
465
|
-
n == @nil_node ? nil :
|
|
585
|
+
n == @nil_node ? nil : n.pair
|
|
466
586
|
end
|
|
467
587
|
|
|
468
588
|
# Returns the key-value pair with the smallest key that is larger than the given key.
|
|
@@ -479,7 +599,7 @@ class RBTree
|
|
|
479
599
|
# tree.succ(7) # => nil (no successor)
|
|
480
600
|
def succ(key)
|
|
481
601
|
n = find_successor_node(key)
|
|
482
|
-
n == @nil_node ? nil :
|
|
602
|
+
n == @nil_node ? nil : n.pair
|
|
483
603
|
end
|
|
484
604
|
|
|
485
605
|
# Validates the red-black tree properties.
|
|
@@ -515,7 +635,7 @@ class RBTree
|
|
|
515
635
|
current = current.left
|
|
516
636
|
end
|
|
517
637
|
current = stack.pop
|
|
518
|
-
yield current.
|
|
638
|
+
yield current.pair
|
|
519
639
|
current = current.right
|
|
520
640
|
end
|
|
521
641
|
end
|
|
@@ -534,7 +654,7 @@ class RBTree
|
|
|
534
654
|
current = current.right
|
|
535
655
|
end
|
|
536
656
|
current = stack.pop
|
|
537
|
-
yield current.
|
|
657
|
+
yield current.pair
|
|
538
658
|
current = current.left
|
|
539
659
|
end
|
|
540
660
|
end
|
|
@@ -550,7 +670,7 @@ class RBTree
|
|
|
550
670
|
|
|
551
671
|
traverse_lt(node.left, key, &block)
|
|
552
672
|
if (node.key <=> key) < 0
|
|
553
|
-
yield node.
|
|
673
|
+
yield node.pair
|
|
554
674
|
traverse_lt(node.right, key, &block)
|
|
555
675
|
end
|
|
556
676
|
end
|
|
@@ -566,7 +686,7 @@ class RBTree
|
|
|
566
686
|
|
|
567
687
|
traverse_lte(node.left, key, &block)
|
|
568
688
|
if (node.key <=> key) <= 0
|
|
569
|
-
yield node.
|
|
689
|
+
yield node.pair
|
|
570
690
|
traverse_lte(node.right, key, &block)
|
|
571
691
|
end
|
|
572
692
|
end
|
|
@@ -582,7 +702,7 @@ class RBTree
|
|
|
582
702
|
|
|
583
703
|
if (node.key <=> key) > 0
|
|
584
704
|
traverse_gt(node.left, key, &block)
|
|
585
|
-
yield node.
|
|
705
|
+
yield node.pair
|
|
586
706
|
end
|
|
587
707
|
traverse_gt(node.right, key, &block)
|
|
588
708
|
end
|
|
@@ -598,7 +718,7 @@ class RBTree
|
|
|
598
718
|
|
|
599
719
|
if (node.key <=> key) >= 0
|
|
600
720
|
traverse_gte(node.left, key, &block)
|
|
601
|
-
yield node.
|
|
721
|
+
yield node.pair
|
|
602
722
|
end
|
|
603
723
|
traverse_gte(node.right, key, &block)
|
|
604
724
|
end
|
|
@@ -622,7 +742,7 @@ class RBTree
|
|
|
622
742
|
less = include_max ? (node.key <=> max) <= 0 : (node.key <=> max) < 0
|
|
623
743
|
|
|
624
744
|
if greater && less
|
|
625
|
-
yield node.
|
|
745
|
+
yield node.pair
|
|
626
746
|
end
|
|
627
747
|
|
|
628
748
|
if (node.key <=> max) < 0
|
|
@@ -641,7 +761,7 @@ class RBTree
|
|
|
641
761
|
|
|
642
762
|
if (node.key <=> key) < 0
|
|
643
763
|
traverse_lt_desc(node.right, key, &block)
|
|
644
|
-
yield node.
|
|
764
|
+
yield node.pair
|
|
645
765
|
end
|
|
646
766
|
traverse_lt_desc(node.left, key, &block)
|
|
647
767
|
end
|
|
@@ -657,7 +777,7 @@ class RBTree
|
|
|
657
777
|
|
|
658
778
|
if (node.key <=> key) <= 0
|
|
659
779
|
traverse_lte_desc(node.right, key, &block)
|
|
660
|
-
yield node.
|
|
780
|
+
yield node.pair
|
|
661
781
|
end
|
|
662
782
|
traverse_lte_desc(node.left, key, &block)
|
|
663
783
|
end
|
|
@@ -673,7 +793,7 @@ class RBTree
|
|
|
673
793
|
|
|
674
794
|
traverse_gt_desc(node.right, key, &block)
|
|
675
795
|
if (node.key <=> key) > 0
|
|
676
|
-
yield node.
|
|
796
|
+
yield node.pair
|
|
677
797
|
traverse_gt_desc(node.left, key, &block)
|
|
678
798
|
end
|
|
679
799
|
end
|
|
@@ -689,7 +809,7 @@ class RBTree
|
|
|
689
809
|
|
|
690
810
|
traverse_gte_desc(node.right, key, &block)
|
|
691
811
|
if (node.key <=> key) >= 0
|
|
692
|
-
yield node.
|
|
812
|
+
yield node.pair
|
|
693
813
|
traverse_gte_desc(node.left, key, &block)
|
|
694
814
|
end
|
|
695
815
|
end
|
|
@@ -714,7 +834,7 @@ class RBTree
|
|
|
714
834
|
less = include_max ? (node.key <=> max) <= 0 : (node.key <=> max) < 0
|
|
715
835
|
|
|
716
836
|
if greater && less
|
|
717
|
-
yield node.
|
|
837
|
+
yield node.pair
|
|
718
838
|
end
|
|
719
839
|
|
|
720
840
|
if (node.key <=> min) > 0
|
|
@@ -1011,6 +1131,16 @@ class RBTree
|
|
|
1011
1131
|
predecessor
|
|
1012
1132
|
end
|
|
1013
1133
|
|
|
1134
|
+
# Finds the node with the largest key that is smaller than the given key.
|
|
1135
|
+
# Returns the key-value pair if found, or nil if the tree is empty.
|
|
1136
|
+
#
|
|
1137
|
+
# @param key [Object] the reference key
|
|
1138
|
+
# @return [Array(Object, Object), nil] the key-value pair, or nil if tree is empty
|
|
1139
|
+
def find_predecessor(key)
|
|
1140
|
+
n = find_predecessor_node(key)
|
|
1141
|
+
n == @nil_node ? nil : n.pair
|
|
1142
|
+
end
|
|
1143
|
+
|
|
1014
1144
|
# Finds the node with the smallest key that is larger than the given key.
|
|
1015
1145
|
#
|
|
1016
1146
|
# If the key exists in the tree, returns its successor node.
|
|
@@ -1051,6 +1181,16 @@ class RBTree
|
|
|
1051
1181
|
successor
|
|
1052
1182
|
end
|
|
1053
1183
|
|
|
1184
|
+
# Finds the node with the smallest key that is larger than the given key.
|
|
1185
|
+
# Returns the key-value pair if found, or nil if the tree is empty.
|
|
1186
|
+
#
|
|
1187
|
+
# @param key [Object] the reference key
|
|
1188
|
+
# @return [Array(Object, Object), nil] the key-value pair, or nil if tree is empty
|
|
1189
|
+
def find_successor(key)
|
|
1190
|
+
n = find_successor_node(key)
|
|
1191
|
+
n == @nil_node ? nil : n.pair
|
|
1192
|
+
end
|
|
1193
|
+
|
|
1054
1194
|
# Finds the leftmost (minimum) node in a subtree.
|
|
1055
1195
|
#
|
|
1056
1196
|
# @param node [Node] the root of the subtree
|
|
@@ -1062,6 +1202,11 @@ class RBTree
|
|
|
1062
1202
|
node
|
|
1063
1203
|
end
|
|
1064
1204
|
|
|
1205
|
+
# Returns the minimum key-value pair.
|
|
1206
|
+
#
|
|
1207
|
+
# @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
|
|
1208
|
+
def find_min = @min_node == @nil_node ? nil : @min_node.pair
|
|
1209
|
+
|
|
1065
1210
|
# Finds the rightmost (maximum) node in a subtree.
|
|
1066
1211
|
#
|
|
1067
1212
|
# @param node [Node] the root of the subtree
|
|
@@ -1073,6 +1218,11 @@ class RBTree
|
|
|
1073
1218
|
node
|
|
1074
1219
|
end
|
|
1075
1220
|
|
|
1221
|
+
# Returns the maximum key-value pair.
|
|
1222
|
+
#
|
|
1223
|
+
# @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
|
|
1224
|
+
def find_max = (n = rightmost(@root)) == @nil_node ? nil : n.pair
|
|
1225
|
+
|
|
1076
1226
|
# Performs a left rotation on the given node.
|
|
1077
1227
|
#
|
|
1078
1228
|
# Transforms the tree structure:
|
|
@@ -1304,8 +1454,8 @@ class MultiRBTree < RBTree
|
|
|
1304
1454
|
# tree.insert(1, 'second')
|
|
1305
1455
|
# tree.get_all(1).to_a # => ["first", "second"]
|
|
1306
1456
|
def get_all(key)
|
|
1307
|
-
|
|
1308
|
-
|
|
1457
|
+
return enum_for(:get_all, key) unless block_given?
|
|
1458
|
+
@hash_index[key]&.value&.each { |v| yield v }
|
|
1309
1459
|
end
|
|
1310
1460
|
|
|
1311
1461
|
# Inserts a value for the given key.
|
|
@@ -1467,18 +1617,75 @@ class MultiRBTree < RBTree
|
|
|
1467
1617
|
[n.key, last ? n.value.last : n.value.first]
|
|
1468
1618
|
end
|
|
1469
1619
|
|
|
1470
|
-
def
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1620
|
+
def each(reverse: false, safe: false, &block)
|
|
1621
|
+
return enum_for(:each, reverse: reverse, safe: safe) unless block_given?
|
|
1622
|
+
if safe
|
|
1623
|
+
super do |k, vals|
|
|
1624
|
+
vals.send(reverse ? :reverse_each : :each) { |v| yield k, v }
|
|
1625
|
+
end
|
|
1626
|
+
else
|
|
1627
|
+
super
|
|
1628
|
+
end
|
|
1474
1629
|
end
|
|
1475
1630
|
|
|
1476
|
-
def
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1631
|
+
def lt(key, reverse: false, safe: false, &block)
|
|
1632
|
+
return enum_for(:lt, key, reverse: reverse, safe: safe) unless block_given?
|
|
1633
|
+
if safe
|
|
1634
|
+
super do |k, vals|
|
|
1635
|
+
vals.send(reverse ? :reverse_each : :each) { |v| yield k, v }
|
|
1636
|
+
end
|
|
1637
|
+
else
|
|
1638
|
+
super
|
|
1639
|
+
end
|
|
1480
1640
|
end
|
|
1481
1641
|
|
|
1642
|
+
def lte(key, reverse: false, safe: false, &block)
|
|
1643
|
+
return enum_for(:lte, key, reverse: reverse, safe: safe) unless block_given?
|
|
1644
|
+
if safe
|
|
1645
|
+
super do |k, vals|
|
|
1646
|
+
vals.send(reverse ? :reverse_each : :each) { |v| yield k, v }
|
|
1647
|
+
end
|
|
1648
|
+
else
|
|
1649
|
+
super
|
|
1650
|
+
end
|
|
1651
|
+
end
|
|
1652
|
+
|
|
1653
|
+
def gt(key, reverse: false, safe: false, &block)
|
|
1654
|
+
return enum_for(:gt, key, reverse: reverse, safe: safe) unless block_given?
|
|
1655
|
+
if safe
|
|
1656
|
+
super do |k, vals|
|
|
1657
|
+
vals.send(reverse ? :reverse_each : :each) { |v| yield k, v }
|
|
1658
|
+
end
|
|
1659
|
+
else
|
|
1660
|
+
super
|
|
1661
|
+
end
|
|
1662
|
+
end
|
|
1663
|
+
|
|
1664
|
+
def gte(key, reverse: false, safe: false, &block)
|
|
1665
|
+
return enum_for(:gte, key, reverse: reverse, safe: safe) unless block_given?
|
|
1666
|
+
if safe
|
|
1667
|
+
super do |k, vals|
|
|
1668
|
+
vals.send(reverse ? :reverse_each : :each) { |v| yield k, v }
|
|
1669
|
+
end
|
|
1670
|
+
else
|
|
1671
|
+
super
|
|
1672
|
+
end
|
|
1673
|
+
end
|
|
1674
|
+
|
|
1675
|
+
def between(min, max, include_min: true, include_max: true, reverse: false, safe: false, &block)
|
|
1676
|
+
return enum_for(:between, min, max, include_min: include_min, include_max: include_max, reverse: reverse, safe: safe) unless block_given?
|
|
1677
|
+
if safe
|
|
1678
|
+
super do |k, vals|
|
|
1679
|
+
vals.send(reverse ? :reverse_each : :each) { |v| yield k, v }
|
|
1680
|
+
end
|
|
1681
|
+
else
|
|
1682
|
+
super
|
|
1683
|
+
end
|
|
1684
|
+
end
|
|
1685
|
+
|
|
1686
|
+
def prev(key, last: false) = (n = super) && [n.key, last ? n.value.last : n.value.first]
|
|
1687
|
+
def succ(key, last: false) = (n = super) && [n.key, last ? n.value.last : n.value.first]
|
|
1688
|
+
|
|
1482
1689
|
private
|
|
1483
1690
|
|
|
1484
1691
|
def traverse_asc(node, &block)
|
|
@@ -1678,4 +1885,8 @@ class RBTree::Node
|
|
|
1678
1885
|
# Checks if the node is black.
|
|
1679
1886
|
# @return [Boolean] true if black, false otherwise
|
|
1680
1887
|
def black? = @color == BLACK
|
|
1888
|
+
|
|
1889
|
+
# Returns the key-value pair.
|
|
1890
|
+
# @return [Array(Object, Object)] the key-value pair
|
|
1891
|
+
def pair = [key, value]
|
|
1681
1892
|
end
|