rbtree-ruby 0.2.0 → 0.2.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ea4c407bb808b5f0ce61e05d95bdb1b9a7efce1a6db4ef6c5688016d39eb66a1
4
- data.tar.gz: 1dec0818d2844494de2daf36cca3b018d28589316b580d71879756e34ca3adb0
3
+ metadata.gz: 13b088e9f0f8ab5cf80a77b8f9b8e1af73b94b33bdff90115fe575def2c54b11
4
+ data.tar.gz: 51636a7c22c4ccc70d2ac14bafc58a39bbccac7599a704506c280d8d39345117
5
5
  SHA512:
6
- metadata.gz: 654691a199723dd0b7426fea9165b372f4c71bcdadc8a58a90b76352b8eaade41145270ff6f88ffb37a4a22732a46b636d21515a07d4ae18b061c5d6fb154d53
7
- data.tar.gz: 8e619ef4f92f440e92350748bfaadc80dc65f8a1daed06d6df1b73e20c4228ee943677496f56e9a8e413cb7081b8d98e6c7711a0b6ffe50fcbf8ab00bb65ed5a
6
+ metadata.gz: e543801d0b22de4ee8654f7b8164121c2107ccda64bc16f47d034e98526703e4aa444e03cecd225bddb9aa9fc5547813bcd1bc73cd4a4048df98eee5d41a2fc6
7
+ data.tar.gz: 6d6986550fe2293e971558e65119f230c3eb26e8f43f8af77fe8bf666d5df337c6bf23e36a4e4fd7e8aee86287b6f58579e48a637e66d27a6e80ab66b0010ed4
data/CHANGELOG.md CHANGED
@@ -5,6 +5,38 @@ 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.2] - 2026-01-14
9
+
10
+ ### Changed
11
+ - **Iterative Traversal (Complete)**: All traversal methods (`lt`, `lte`, `gt`, `gte`, `between` and their `_desc` variants) now use an iterative stack-based approach instead of recursion.
12
+ - Ensures deep trees can be traversed without `SystemStackError`.
13
+ - Applies to both `RBTree` and `MultiRBTree`.
14
+ - **Code Deduplication**: Unified traversal logic between `RBTree` and `MultiRBTree` for better maintainability.
15
+ - **Documentation**: Minor typo fixes.
16
+
17
+ ### Fixed
18
+ - **MultiRBTree#prev / #succ**: Fixed incorrect use of bare `super` which forwarded keyword arguments to parent methods that don't accept them. Also fixed incorrect access to parent return value (was treating `[key, value]` pair as a node object).
19
+ - **MultiRBTree#shift / #pop hash index leak**: When `shift` or `pop` removed the last value for a key, the key remained in the internal hash index (`@hash_index`). Now correctly uses `delete_node(key)` instead of `remove_node(node)` to ensure hash index consistency.
20
+
21
+ ## [0.2.1] - 2026-01-14
22
+
23
+ ### Added
24
+ - **Enhanced iteration**: `each` now accepts `reverse:` and `safe:` options
25
+ - `tree.each(reverse: true) { ... }` (same as `reverse_each`)
26
+ - `tree.each(safe: true) { ... }` (modification-safe)
27
+ - `tree.each(reverse: true, safe: true) { ... }` (reverse modification-safe)
28
+ - In `MultiRBTree`, `reverse: true` also iterates over values in reverse insertion order.
29
+ - **Range query safe mode**: `safe:` option for `lt`, `lte`, `gt`, `gte`, `between`
30
+ - `tree.lt(10, safe: true) { |k, _| tree.delete(k) if k.even? }`
31
+ - Works with `:reverse` option: `tree.gt(5, reverse: true, safe: true)`
32
+ - Returns Enumerator: `tree.between(1, 100, safe: true).select { ... }`
33
+
34
+ ### Changed
35
+ - **MultiRBTree#get_all**: Now returns an `Enumerator` instead of an `Array` when no block is given.
36
+ - Improves consistency with other iteration methods.
37
+ - Safe handling for non-existent keys (returns empty Enumerator/nil logic handled safely).
38
+ - Use `.to_a` to get an Array: `tree.get_all(key).to_a`
39
+
8
40
  ## [0.2.0] - 2026-01-14
9
41
 
10
42
  ### 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 key-value storage with O(log n) time complexity for insertion, deletion, and lookup operations.
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}" }
@@ -2,5 +2,5 @@
2
2
 
3
3
  class RBTree
4
4
  # The version of the rbtree-ruby gem
5
- VERSION = "0.2.0"
5
+ VERSION = "0.2.2"
6
6
  end
data/lib/rbtree.rb CHANGED
@@ -112,26 +112,27 @@ class RBTree
112
112
  end
113
113
  end
114
114
 
115
- # Returns a string representation of the tree.
116
- #
117
- # Shows the first 5 entries and total size. Useful for debugging.
118
- #
119
- # @return [String] a human-readable representation of the tree
120
- def inspect
121
- if @size > 0
122
- content = first(5).map { |k, v| "#{k.inspect}=>#{v.inspect}" }.join(", ")
123
- suffix = @size > 5 ? ", ..." : ""
124
- "#<#{self.class}:0x#{object_id.to_s(16)} size=#{@size} {#{content}#{suffix}}>"
125
- else
126
- super
127
- end
128
- end
129
-
130
115
  # Checks if the tree is empty.
131
116
  #
132
117
  # @return [Boolean] true if the tree contains no elements, false otherwise
133
118
  def empty? = @root == @nil_node
134
119
 
120
+ # Returns the minimum key-value pair without removing it.
121
+ #
122
+ # @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
123
+ # @example
124
+ # tree = RBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
125
+ # tree.min # => [1, "one"]
126
+ def min = find_min
127
+
128
+ # Returns the maximum key-value pair without removing it.
129
+ #
130
+ # @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
131
+ # @example
132
+ # tree = RBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
133
+ # tree.max # => [3, "three"]
134
+ def max = find_max
135
+
135
136
  # Checks if the tree contains the given key.
136
137
  #
137
138
  # @param key [Object] the key to search for
@@ -158,6 +159,58 @@ class RBTree
158
159
  end
159
160
  alias_method :[], :get
160
161
 
162
+ # Returns the key-value pair with the key closest to the given key.
163
+ #
164
+ # This method requires keys to be numeric or support subtraction and abs methods.
165
+ # If multiple keys have the same distance, the one with the smaller key is returned.
166
+ #
167
+ # @param key [Numeric] the target key
168
+ # @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
169
+ # @example
170
+ # tree = RBTree.new({1 => 'one', 5 => 'five', 10 => 'ten'})
171
+ # tree.nearest(4) # => [5, "five"]
172
+ # tree.nearest(7) # => [5, "five"]
173
+ # tree.nearest(8) # => [10, "ten"]
174
+ def nearest(key)
175
+ return nil unless key.respond_to?(:-)
176
+ n = find_nearest_node(key)
177
+ n == @nil_node ? nil : n.pair
178
+ end
179
+
180
+ # Returns the key-value pair with the largest key that is smaller than the given key.
181
+ #
182
+ # If the key exists in the tree, returns the predecessor (previous element).
183
+ # If the key does not exist, returns the largest key-value pair with key < given key.
184
+ #
185
+ # @param key [Object] the reference key
186
+ # @return [Array(Object, Object), nil] a two-element array [key, value], or nil if no predecessor exists
187
+ # @example
188
+ # tree = RBTree.new({1 => 'one', 3 => 'three', 5 => 'five', 7 => 'seven'})
189
+ # tree.prev(5) # => [3, "three"]
190
+ # tree.prev(4) # => [3, "three"] (4 does not exist)
191
+ # tree.prev(1) # => nil (no predecessor)
192
+ def prev(key)
193
+ n = find_predecessor_node(key)
194
+ n == @nil_node ? nil : n.pair
195
+ end
196
+
197
+ # Returns the key-value pair with the smallest key that is larger than the given key.
198
+ #
199
+ # If the key exists in the tree, returns the successor (next element).
200
+ # If the key does not exist, returns the smallest key-value pair with key > given key.
201
+ #
202
+ # @param key [Object] the reference key
203
+ # @return [Array(Object, Object), nil] a two-element array [key, value], or nil if no successor exists
204
+ # @example
205
+ # tree = RBTree.new({1 => 'one', 3 => 'three', 5 => 'five', 7 => 'seven'})
206
+ # tree.succ(5) # => [7, "seven"]
207
+ # tree.succ(4) # => [5, "five"] (4 does not exist)
208
+ # tree.succ(7) # => nil (no successor)
209
+ def succ(key)
210
+ n = find_successor_node(key)
211
+ n == @nil_node ? nil : n.pair
212
+ end
213
+
161
214
  # Inserts or updates a key-value pair in the tree.
162
215
  #
163
216
  # If the key already exists and overwrite is true (default), the value is updated.
@@ -233,17 +286,6 @@ class RBTree
233
286
  value
234
287
  end
235
288
 
236
- # Removes all key-value pairs from the tree.
237
- #
238
- # @return [RBTree] self
239
- def clear
240
- @root = @nil_node
241
- @min_node = @nil_node
242
- @hash_index.clear
243
- @size = 0
244
- self
245
- end
246
-
247
289
  # Removes and returns the minimum key-value pair.
248
290
  #
249
291
  # @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
@@ -268,13 +310,26 @@ class RBTree
268
310
  def pop
269
311
  n = rightmost(@root)
270
312
  return nil if n == @nil_node
271
- result = [n.key, n.value]
313
+ result = n.pair
272
314
  delete(n.key)
273
315
  result
274
316
  end
275
317
 
276
- # Iterates over all key-value pairs in ascending order of keys.
318
+ # Removes all key-value pairs from the tree.
319
+ #
320
+ # @return [RBTree] self
321
+ def clear
322
+ @root = @nil_node
323
+ @min_node = @nil_node
324
+ @hash_index.clear
325
+ @size = 0
326
+ self
327
+ end
328
+
329
+ # Iterates over all key-value pairs in ascending (or descending) order.
277
330
  #
331
+ # @param reverse [Boolean] if true, iterate in descending order (default: false)
332
+ # @param safe [Boolean] if true, safe for modifications during iteration (default: false)
278
333
  # @yield [key, value] each key-value pair in the tree
279
334
  # @return [Enumerator, RBTree] an Enumerator if no block is given, self otherwise
280
335
  # @example
@@ -284,9 +339,22 @@ class RBTree
284
339
  # # 1: one
285
340
  # # 2: two
286
341
  # # 3: three
287
- def each(&block)
288
- return enum_for(:each) unless block_given?
289
- traverse_asc(@root, &block)
342
+ #
343
+ # # Reverse iteration
344
+ # tree.each(reverse: true) { |k, v| ... }
345
+ #
346
+ # # Safe iteration for modifications
347
+ # tree.each(safe: true) do |k, v|
348
+ # tree.delete(k) if k.even?
349
+ # end
350
+ def each(reverse: false, safe: false, &block)
351
+ return enum_for(:each, reverse: reverse, safe: safe) unless block_given?
352
+ if reverse
353
+ traverse_all_desc(@root, safe: safe, &block)
354
+ else
355
+ traverse_all_asc(@root, safe: safe, &block)
356
+ end
357
+ self
290
358
  end
291
359
 
292
360
  # Iterates over all key-value pairs in descending order of keys.
@@ -300,49 +368,34 @@ class RBTree
300
368
  # # 3: three
301
369
  # # 2: two
302
370
  # # 1: one
303
- def reverse_each(&block)
304
- return enum_for(:reverse_each) unless block_given?
305
- traverse_desc(@root, &block)
306
- end
307
-
308
- # Returns the minimum key-value pair without removing it.
371
+ # Iterates over all key-value pairs in descending order of keys.
309
372
  #
310
- # @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
311
- # @example
312
- # tree = RBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
313
- # tree.min # => [1, "one"]
314
- def min
315
- @min_node == @nil_node ? nil : [@min_node.key, @min_node.value]
316
- end
317
-
318
- # Returns the maximum key-value pair without removing it.
373
+ # This is an alias for `each(reverse: true)`.
319
374
  #
320
- # @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
321
- # @example
322
- # tree = RBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
323
- # tree.max # => [3, "three"]
324
- def max
325
- n = rightmost(@root)
326
- n == @nil_node ? nil : [n.key, n.value]
327
- end
375
+ # @param safe [Boolean] if true, safe for modifications during iteration (default: false)
376
+ # @yield [key, value] each key-value pair in the tree
377
+ # @return [Enumerator, RBTree] an Enumerator if no block is given, self otherwise
378
+ # @see #each
379
+ def reverse_each(safe: false, &block) = each(reverse: true, safe: safe, &block)
328
380
 
329
381
  # Retrieves all key-value pairs with keys less than the specified key.
330
382
  #
331
383
  # @param key [Object] the upper bound (exclusive)
332
384
  # @param reverse [Boolean] if true, iterate in descending order (default: false)
385
+ # @param safe [Boolean] if true, safe for modifications during iteration (default: false)
333
386
  # @yield [key, value] each matching key-value pair (if block given)
334
387
  # @return [Enumerator, RBTree] Enumerator if no block given, self otherwise
335
388
  # @example
336
389
  # tree = RBTree.new({1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four'})
337
390
  # tree.lt(3).to_a # => [[1, "one"], [2, "two"]]
338
391
  # tree.lt(3, reverse: true).first # => [2, "two"]
339
- # tree.lt(3) { |k, v| puts k } # prints keys, returns self
340
- def lt(key, reverse: false, &block)
341
- return enum_for(:lt, key, reverse: reverse) unless block_given?
392
+ # tree.lt(3, safe: true) { |k, _| tree.delete(k) if k.even? } # safe to delete
393
+ def lt(key, reverse: false, safe: false, &block)
394
+ return enum_for(:lt, key, reverse: reverse, safe: safe) unless block_given?
342
395
  if reverse
343
- traverse_lt_desc(@root, key, &block)
396
+ traverse_lt_desc(@root, key, safe: safe, &block)
344
397
  else
345
- traverse_lt(@root, key, &block)
398
+ traverse_lt_asc(@root, key, safe: safe, &block)
346
399
  end
347
400
  self
348
401
  end
@@ -351,18 +404,19 @@ class RBTree
351
404
  #
352
405
  # @param key [Object] the upper bound (inclusive)
353
406
  # @param reverse [Boolean] if true, iterate in descending order (default: false)
407
+ # @param safe [Boolean] if true, safe for modifications during iteration (default: false)
354
408
  # @yield [key, value] each matching key-value pair (if block given)
355
409
  # @return [Enumerator, RBTree] Enumerator if no block given, self otherwise
356
410
  # @example
357
411
  # tree = RBTree.new({1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four'})
358
412
  # tree.lte(3).to_a # => [[1, "one"], [2, "two"], [3, "three"]]
359
413
  # 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?
414
+ def lte(key, reverse: false, safe: false, &block)
415
+ return enum_for(:lte, key, reverse: reverse, safe: safe) unless block_given?
362
416
  if reverse
363
- traverse_lte_desc(@root, key, &block)
417
+ traverse_lte_desc(@root, key, safe: safe, &block)
364
418
  else
365
- traverse_lte(@root, key, &block)
419
+ traverse_lte_asc(@root, key, safe: safe, &block)
366
420
  end
367
421
  self
368
422
  end
@@ -371,18 +425,19 @@ class RBTree
371
425
  #
372
426
  # @param key [Object] the lower bound (exclusive)
373
427
  # @param reverse [Boolean] if true, iterate in descending order (default: false)
428
+ # @param safe [Boolean] if true, safe for modifications during iteration (default: false)
374
429
  # @yield [key, value] each matching key-value pair (if block given)
375
430
  # @return [Enumerator, RBTree] Enumerator if no block given, self otherwise
376
431
  # @example
377
432
  # tree = RBTree.new({1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four'})
378
433
  # tree.gt(2).to_a # => [[3, "three"], [4, "four"]]
379
434
  # 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?
435
+ def gt(key, reverse: false, safe: false, &block)
436
+ return enum_for(:gt, key, reverse: reverse, safe: safe) unless block_given?
382
437
  if reverse
383
- traverse_gt_desc(@root, key, &block)
438
+ traverse_gt_desc(@root, key, safe: safe, &block)
384
439
  else
385
- traverse_gt(@root, key, &block)
440
+ traverse_gt_asc(@root, key, safe: safe, &block)
386
441
  end
387
442
  self
388
443
  end
@@ -391,18 +446,19 @@ class RBTree
391
446
  #
392
447
  # @param key [Object] the lower bound (inclusive)
393
448
  # @param reverse [Boolean] if true, iterate in descending order (default: false)
449
+ # @param safe [Boolean] if true, safe for modifications during iteration (default: false)
394
450
  # @yield [key, value] each matching key-value pair (if block given)
395
451
  # @return [Enumerator, RBTree] Enumerator if no block given, self otherwise
396
452
  # @example
397
453
  # tree = RBTree.new({1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four'})
398
454
  # tree.gte(2).to_a # => [[2, "two"], [3, "three"], [4, "four"]]
399
455
  # 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?
456
+ def gte(key, reverse: false, safe: false, &block)
457
+ return enum_for(:gte, key, reverse: reverse, safe: safe) unless block_given?
402
458
  if reverse
403
- traverse_gte_desc(@root, key, &block)
459
+ traverse_gte_desc(@root, key, safe: safe, &block)
404
460
  else
405
- traverse_gte(@root, key, &block)
461
+ traverse_gte_asc(@root, key, safe: safe, &block)
406
462
  end
407
463
  self
408
464
  end
@@ -414,72 +470,36 @@ class RBTree
414
470
  # @param include_min [Boolean] whether to include the lower bound (default: true)
415
471
  # @param include_max [Boolean] whether to include the upper bound (default: true)
416
472
  # @param reverse [Boolean] if true, iterate in descending order (default: false)
473
+ # @param safe [Boolean] if true, safe for modifications during iteration (default: false)
417
474
  # @yield [key, value] each matching key-value pair (if block given)
418
475
  # @return [Enumerator, RBTree] Enumerator if no block given, self otherwise
419
476
  # @example
420
477
  # tree = RBTree.new({1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four', 5 => 'five'})
421
478
  # tree.between(2, 4).to_a # => [[2, "two"], [3, "three"], [4, "four"]]
422
479
  # 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?
480
+ def between(min, max, include_min: true, include_max: true, reverse: false, safe: false, &block)
481
+ return enum_for(:between, min, max, include_min: include_min, include_max: include_max, reverse: reverse, safe: safe) unless block_given?
425
482
  if reverse
426
- traverse_between_desc(@root, min, max, include_min, include_max, &block)
483
+ traverse_between_desc(@root, min, max, include_min, include_max, safe: safe, &block)
427
484
  else
428
- traverse_between(@root, min, max, include_min, include_max, &block)
485
+ traverse_between_asc(@root, min, max, include_min, include_max, safe: safe, &block)
429
486
  end
430
487
  self
431
488
  end
432
489
 
433
- # Returns the key-value pair with the key closest to the given key.
434
- #
435
- # This method requires keys to be numeric or support subtraction and abs methods.
436
- # If multiple keys have the same distance, the one with the smaller key is returned.
437
- #
438
- # @param key [Numeric] the target key
439
- # @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
440
- # @example
441
- # tree = RBTree.new({1 => 'one', 5 => 'five', 10 => 'ten'})
442
- # tree.nearest(4) # => [5, "five"]
443
- # tree.nearest(7) # => [5, "five"]
444
- # tree.nearest(8) # => [10, "ten"]
445
- def nearest(key)
446
- return nil unless key.respond_to?(:-)
447
- n = find_nearest_node(key)
448
- n == @nil_node ? nil : [n.key, n.value]
449
- end
450
-
451
- # Returns the key-value pair with the largest key that is smaller than the given key.
452
- #
453
- # If the key exists in the tree, returns the predecessor (previous element).
454
- # If the key does not exist, returns the largest key-value pair with key < given key.
455
- #
456
- # @param key [Object] the reference key
457
- # @return [Array(Object, Object), nil] a two-element array [key, value], or nil if no predecessor exists
458
- # @example
459
- # tree = RBTree.new({1 => 'one', 3 => 'three', 5 => 'five', 7 => 'seven'})
460
- # tree.prev(5) # => [3, "three"]
461
- # tree.prev(4) # => [3, "three"] (4 does not exist)
462
- # tree.prev(1) # => nil (no predecessor)
463
- def prev(key)
464
- n = find_predecessor_node(key)
465
- n == @nil_node ? nil : [n.key, n.value]
466
- end
467
-
468
- # Returns the key-value pair with the smallest key that is larger than the given key.
490
+ # Returns a string representation of the tree.
469
491
  #
470
- # If the key exists in the tree, returns the successor (next element).
471
- # If the key does not exist, returns the smallest key-value pair with key > given key.
492
+ # Shows the first 5 entries and total size. Useful for debugging.
472
493
  #
473
- # @param key [Object] the reference key
474
- # @return [Array(Object, Object), nil] a two-element array [key, value], or nil if no successor exists
475
- # @example
476
- # tree = RBTree.new({1 => 'one', 3 => 'three', 5 => 'five', 7 => 'seven'})
477
- # tree.succ(5) # => [7, "seven"]
478
- # tree.succ(4) # => [5, "five"] (4 does not exist)
479
- # tree.succ(7) # => nil (no successor)
480
- def succ(key)
481
- n = find_successor_node(key)
482
- n == @nil_node ? nil : [n.key, n.value]
494
+ # @return [String] a human-readable representation of the tree
495
+ def inspect
496
+ if @size > 0
497
+ content = first(5).map { |k, v| "#{k.inspect}=>#{v.inspect}" }.join(", ")
498
+ suffix = @size > 5 ? ", ..." : ""
499
+ "#<#{self.class}:0x#{object_id.to_s(16)} size=#{@size} {#{content}#{suffix}}>"
500
+ else
501
+ super
502
+ end
483
503
  end
484
504
 
485
505
  # Validates the red-black tree properties.
@@ -504,56 +524,141 @@ class RBTree
504
524
  # Traverses the tree in ascending order (in-order traversal).
505
525
  #
506
526
  # @param node [Node] the current node
527
+ # @param min [Object] the lower bound (inclusive)
528
+ # @param max [Object] the upper bound (inclusive)
529
+ # @param include_min [Boolean] whether to include the lower bound
530
+ # @param include_max [Boolean] whether to include the upper bound
531
+ # @param safe [Boolean] whether to use safe traversal
507
532
  # @yield [key, value] each key-value pair in ascending order
508
533
  # @return [void]
509
- def traverse_asc(node, &block)
510
- stack = []
511
- current = node
512
- while current != @nil_node || !stack.empty?
513
- while current != @nil_node
514
- stack << current
515
- current = current.left
534
+ def traverse_range_asc(node, min, max, include_min, include_max, safe: false, &block)
535
+ if safe
536
+ pair = !min ? find_min :
537
+ include_min && @hash_index[min]&.pair || find_successor(min)
538
+ if !max
539
+ while pair
540
+ current_key = pair[0]
541
+ yield pair
542
+ pair = find_successor(current_key)
543
+ end
544
+ else
545
+ while pair && pair[0] < max
546
+ current_key = pair[0]
547
+ yield pair
548
+ pair = find_successor(current_key)
549
+ end
550
+ end
551
+ yield pair if pair && max && include_max && pair[0] == max
552
+ else
553
+ stack = []
554
+ current = node
555
+ while current != @nil_node || !stack.empty?
556
+ while current != @nil_node
557
+ if min && ((current.key <=> min) < 0 ||
558
+ (!include_min && (current.key <=> min) == 0))
559
+ current = current.right
560
+ else
561
+ stack << current
562
+ current = current.left
563
+ end
564
+ end
565
+
566
+ if !stack.empty?
567
+ current = stack.pop
568
+
569
+ if max && ((current.key <=> max) > 0 ||
570
+ (!include_max && (current.key <=> max) == 0))
571
+ return
572
+ else
573
+ yield current.pair
574
+ current = current.right
575
+ end
576
+ end
516
577
  end
517
- current = stack.pop
518
- yield current.key, current.value
519
- current = current.right
520
578
  end
521
579
  end
522
580
 
523
581
  # Traverses the tree in descending order (reverse in-order traversal).
524
582
  #
525
583
  # @param node [Node] the current node
584
+ # @param min [Object] the lower bound (inclusive)
585
+ # @param max [Object] the upper bound (inclusive)
586
+ # @param include_min [Boolean] whether to include the lower bound
587
+ # @param include_max [Boolean] whether to include the upper bound
588
+ # @param safe [Boolean] whether to use safe traversal
526
589
  # @yield [key, value] each key-value pair in descending order
527
590
  # @return [void]
528
- def traverse_desc(node, &block)
529
- stack = []
530
- current = node
531
- while current != @nil_node || !stack.empty?
532
- while current != @nil_node
533
- stack << current
534
- current = current.right
591
+ def traverse_range_desc(node, min, max, include_min, include_max, safe: false, &block)
592
+ if safe
593
+ pair = !max ? find_max :
594
+ include_max && @hash_index[max]&.pair || find_predecessor(max)
595
+ if !min
596
+ while pair
597
+ current_key = pair[0]
598
+ yield pair
599
+ pair = find_predecessor(current_key)
600
+ end
601
+ else
602
+ while pair && pair[0] > min
603
+ current_key = pair[0]
604
+ yield pair
605
+ pair = find_predecessor(current_key)
606
+ end
607
+ end
608
+ yield pair if pair && min && include_min && pair[0] == min
609
+ else
610
+ stack = []
611
+ current = node
612
+ while current != @nil_node || !stack.empty?
613
+ while current != @nil_node
614
+ if max && ((current.key <=> max) > 0 ||
615
+ (!include_max && (current.key <=> max) == 0))
616
+ current = current.left
617
+ else
618
+ stack << current
619
+ current = current.right
620
+ end
621
+ end
622
+
623
+ if !stack.empty?
624
+ current = stack.pop
625
+
626
+ if min && ((current.key <=> min) < 0 ||
627
+ (!include_min && (current.key <=> min) == 0))
628
+ return
629
+ else
630
+ yield current.pair
631
+ current = current.left
632
+ end
633
+ end
535
634
  end
536
- current = stack.pop
537
- yield current.key, current.value
538
- current = current.left
539
635
  end
540
636
  end
541
637
 
638
+ # Traverses the tree in ascending order (in-order traversal).
639
+ #
640
+ # @param node [Node] the current node
641
+ # @yield [key, value] each key-value pair in ascending order
642
+ # @return [void]
643
+ def traverse_all_asc(node, safe: false, &block) =
644
+ traverse_range_asc(node, nil, nil, false, false, safe: safe, &block)
645
+
646
+ # Traverses the tree in descending order (reverse in-order traversal).
647
+ #
648
+ # @param node [Node] the current node
649
+ # @yield [key, value] each key-value pair in descending order
650
+ # @return [void]
651
+ def traverse_all_desc(node, safe: false, &block) =
652
+ traverse_range_desc(node, nil, nil, false, false, safe: safe, &block)
653
+
542
654
  # Traverses nodes with keys less than the specified key.
543
655
  #
544
656
  # @param node [Node] the current node
545
657
  # @param key [Object] the upper bound (exclusive)
546
658
  # @yield [key, value] each matching key-value pair
547
659
  # @return [void]
548
- def traverse_lt(node, key, &block)
549
- return if node == @nil_node
550
-
551
- traverse_lt(node.left, key, &block)
552
- if (node.key <=> key) < 0
553
- yield node.key, node.value
554
- traverse_lt(node.right, key, &block)
555
- end
556
- end
660
+ def traverse_lt_asc(node, key, safe: false, &block) =
661
+ traverse_range_asc(node, nil, key, false, false, safe: safe, &block)
557
662
 
558
663
  # Traverses nodes with keys less than or equal to the specified key.
559
664
  #
@@ -561,15 +666,8 @@ class RBTree
561
666
  # @param key [Object] the upper bound (inclusive)
562
667
  # @yield [key, value] each matching key-value pair
563
668
  # @return [void]
564
- def traverse_lte(node, key, &block)
565
- return if node == @nil_node
566
-
567
- traverse_lte(node.left, key, &block)
568
- if (node.key <=> key) <= 0
569
- yield node.key, node.value
570
- traverse_lte(node.right, key, &block)
571
- end
572
- end
669
+ def traverse_lte_asc(node, key, safe: false, &block) =
670
+ traverse_range_asc(node, nil, key, false, true, safe: safe, &block)
573
671
 
574
672
  # Traverses nodes with keys greater than the specified key.
575
673
  #
@@ -577,15 +675,8 @@ class RBTree
577
675
  # @param key [Object] the lower bound (exclusive)
578
676
  # @yield [key, value] each matching key-value pair
579
677
  # @return [void]
580
- def traverse_gt(node, key, &block)
581
- return if node == @nil_node
582
-
583
- if (node.key <=> key) > 0
584
- traverse_gt(node.left, key, &block)
585
- yield node.key, node.value
586
- end
587
- traverse_gt(node.right, key, &block)
588
- end
678
+ def traverse_gt_asc(node, key, safe: false, &block) =
679
+ traverse_range_asc(node, key, nil, false, false, safe: safe, &block)
589
680
 
590
681
  # Traverses nodes with keys greater than or equal to the specified key.
591
682
  #
@@ -593,15 +684,8 @@ class RBTree
593
684
  # @param key [Object] the lower bound (inclusive)
594
685
  # @yield [key, value] each matching key-value pair
595
686
  # @return [void]
596
- def traverse_gte(node, key, &block)
597
- return if node == @nil_node
598
-
599
- if (node.key <=> key) >= 0
600
- traverse_gte(node.left, key, &block)
601
- yield node.key, node.value
602
- end
603
- traverse_gte(node.right, key, &block)
604
- end
687
+ def traverse_gte_asc(node, key, safe: false, &block) =
688
+ traverse_range_asc(node, key, nil, true, false, safe: safe, &block)
605
689
 
606
690
  # Traverses nodes with keys within the specified range.
607
691
  #
@@ -612,23 +696,8 @@ class RBTree
612
696
  # @param include_max [Boolean] whether to include the upper bound
613
697
  # @yield [key, value] each matching key-value pair
614
698
  # @return [void]
615
- def traverse_between(node, min, max, include_min, include_max, &block)
616
- return if node == @nil_node
617
- if (node.key <=> min) > 0
618
- traverse_between(node.left, min, max, include_min, include_max, &block)
619
- end
620
-
621
- greater = include_min ? (node.key <=> min) >= 0 : (node.key <=> min) > 0
622
- less = include_max ? (node.key <=> max) <= 0 : (node.key <=> max) < 0
623
-
624
- if greater && less
625
- yield node.key, node.value
626
- end
627
-
628
- if (node.key <=> max) < 0
629
- traverse_between(node.right, min, max, include_min, include_max, &block)
630
- end
631
- end
699
+ def traverse_between_asc(node, min, max, include_min, include_max, safe: false, &block) =
700
+ traverse_range_asc(node, min, max, include_min, include_max, safe: safe, &block)
632
701
 
633
702
  # Traverses nodes with keys less than the specified key in descending order.
634
703
  #
@@ -636,15 +705,8 @@ class RBTree
636
705
  # @param key [Object] the upper bound (exclusive)
637
706
  # @yield [key, value] each matching key-value pair in descending order
638
707
  # @return [void]
639
- def traverse_lt_desc(node, key, &block)
640
- return if node == @nil_node
641
-
642
- if (node.key <=> key) < 0
643
- traverse_lt_desc(node.right, key, &block)
644
- yield node.key, node.value
645
- end
646
- traverse_lt_desc(node.left, key, &block)
647
- end
708
+ def traverse_lt_desc(node, key, safe: false, &block) =
709
+ traverse_range_desc(node, nil, key, false, false, safe: safe, &block)
648
710
 
649
711
  # Traverses nodes with keys less than or equal to the specified key in descending order.
650
712
  #
@@ -652,15 +714,8 @@ class RBTree
652
714
  # @param key [Object] the upper bound (inclusive)
653
715
  # @yield [key, value] each matching key-value pair in descending order
654
716
  # @return [void]
655
- def traverse_lte_desc(node, key, &block)
656
- return if node == @nil_node
657
-
658
- if (node.key <=> key) <= 0
659
- traverse_lte_desc(node.right, key, &block)
660
- yield node.key, node.value
661
- end
662
- traverse_lte_desc(node.left, key, &block)
663
- end
717
+ def traverse_lte_desc(node, key, safe: false, &block) =
718
+ traverse_range_desc(node, nil, key, false, true, safe: safe, &block)
664
719
 
665
720
  # Traverses nodes with keys greater than the specified key in descending order.
666
721
  #
@@ -668,15 +723,8 @@ class RBTree
668
723
  # @param key [Object] the lower bound (exclusive)
669
724
  # @yield [key, value] each matching key-value pair in descending order
670
725
  # @return [void]
671
- def traverse_gt_desc(node, key, &block)
672
- return if node == @nil_node
673
-
674
- traverse_gt_desc(node.right, key, &block)
675
- if (node.key <=> key) > 0
676
- yield node.key, node.value
677
- traverse_gt_desc(node.left, key, &block)
678
- end
679
- end
726
+ def traverse_gt_desc(node, key, safe: false, &block) =
727
+ traverse_range_desc(node, key, nil, false, false, safe: safe, &block)
680
728
 
681
729
  # Traverses nodes with keys greater than or equal to the specified key in descending order.
682
730
  #
@@ -684,15 +732,8 @@ class RBTree
684
732
  # @param key [Object] the lower bound (inclusive)
685
733
  # @yield [key, value] each matching key-value pair in descending order
686
734
  # @return [void]
687
- def traverse_gte_desc(node, key, &block)
688
- return if node == @nil_node
689
-
690
- traverse_gte_desc(node.right, key, &block)
691
- if (node.key <=> key) >= 0
692
- yield node.key, node.value
693
- traverse_gte_desc(node.left, key, &block)
694
- end
695
- end
735
+ def traverse_gte_desc(node, key, safe: false, &block) =
736
+ traverse_range_desc(node, key, nil, true, false, safe: safe, &block)
696
737
 
697
738
  # Traverses nodes with keys within the specified range in descending order.
698
739
  #
@@ -703,24 +744,8 @@ class RBTree
703
744
  # @param include_max [Boolean] whether to include the upper bound
704
745
  # @yield [key, value] each matching key-value pair in descending order
705
746
  # @return [void]
706
- def traverse_between_desc(node, min, max, include_min, include_max, &block)
707
- return if node == @nil_node
708
-
709
- if (node.key <=> max) < 0
710
- traverse_between_desc(node.right, min, max, include_min, include_max, &block)
711
- end
712
-
713
- greater = include_min ? (node.key <=> min) >= 0 : (node.key <=> min) > 0
714
- less = include_max ? (node.key <=> max) <= 0 : (node.key <=> max) < 0
715
-
716
- if greater && less
717
- yield node.key, node.value
718
- end
719
-
720
- if (node.key <=> min) > 0
721
- traverse_between_desc(node.left, min, max, include_min, include_max, &block)
722
- end
723
- end
747
+ def traverse_between_desc(node, min, max, include_min, include_max, safe: false, &block) =
748
+ traverse_range_desc(node, min, max, include_min, include_max, safe: safe, &block)
724
749
 
725
750
  # Restores red-black tree properties after insertion.
726
751
  #
@@ -1011,6 +1036,16 @@ class RBTree
1011
1036
  predecessor
1012
1037
  end
1013
1038
 
1039
+ # Finds the node with the largest key that is smaller than the given key.
1040
+ # Returns the key-value pair if found, or nil if the tree is empty.
1041
+ #
1042
+ # @param key [Object] the reference key
1043
+ # @return [Array(Object, Object), nil] the key-value pair, or nil if tree is empty
1044
+ def find_predecessor(key)
1045
+ n = find_predecessor_node(key)
1046
+ n == @nil_node ? nil : n.pair
1047
+ end
1048
+
1014
1049
  # Finds the node with the smallest key that is larger than the given key.
1015
1050
  #
1016
1051
  # If the key exists in the tree, returns its successor node.
@@ -1051,6 +1086,16 @@ class RBTree
1051
1086
  successor
1052
1087
  end
1053
1088
 
1089
+ # Finds the node with the smallest key that is larger than the given key.
1090
+ # Returns the key-value pair if found, or nil if the tree is empty.
1091
+ #
1092
+ # @param key [Object] the reference key
1093
+ # @return [Array(Object, Object), nil] the key-value pair, or nil if tree is empty
1094
+ def find_successor(key)
1095
+ n = find_successor_node(key)
1096
+ n == @nil_node ? nil : n.pair
1097
+ end
1098
+
1054
1099
  # Finds the leftmost (minimum) node in a subtree.
1055
1100
  #
1056
1101
  # @param node [Node] the root of the subtree
@@ -1062,6 +1107,11 @@ class RBTree
1062
1107
  node
1063
1108
  end
1064
1109
 
1110
+ # Returns the minimum key-value pair.
1111
+ #
1112
+ # @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
1113
+ def find_min = @min_node == @nil_node ? nil : @min_node.pair
1114
+
1065
1115
  # Finds the rightmost (maximum) node in a subtree.
1066
1116
  #
1067
1117
  # @param node [Node] the root of the subtree
@@ -1073,6 +1123,11 @@ class RBTree
1073
1123
  node
1074
1124
  end
1075
1125
 
1126
+ # Returns the maximum key-value pair.
1127
+ #
1128
+ # @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
1129
+ def find_max = (n = rightmost(@root)) == @nil_node ? nil : n.pair
1130
+
1076
1131
  # Performs a left rotation on the given node.
1077
1132
  #
1078
1133
  # Transforms the tree structure:
@@ -1257,6 +1312,17 @@ end
1257
1312
  # @author Masahito Suzuki
1258
1313
  # @since 0.1.2
1259
1314
  class MultiRBTree < RBTree
1315
+ def min(last: false)
1316
+ return nil if @min_node == @nil_node || @min_node.value.empty?
1317
+ [@min_node.key, last ? @min_node.value.last : @min_node.value.first]
1318
+ end
1319
+
1320
+ def max(last: false)
1321
+ n = rightmost(@root)
1322
+ return nil if n == @nil_node || n.value.empty?
1323
+ [n.key, last ? n.value.last : n.value.first]
1324
+ end
1325
+
1260
1326
  # Retrieves a value associated with the given key.
1261
1327
  #
1262
1328
  # @param key [Object] the key to look up
@@ -1286,26 +1352,22 @@ class MultiRBTree < RBTree
1286
1352
  # @return [Object, nil] the last value for the key, or nil if not found
1287
1353
  def get_last(key) = get(key, last: true)
1288
1354
 
1289
- # Returns the first value for the given key (for Hash-like access).
1290
- #
1291
- # Note: Unlike get(), this method does not accept options.
1292
- #
1293
- # @param key [Object] the key to look up
1294
- # @return [Object, nil] the first value for the key, or nil if not found
1295
- def [](key) = get(key)
1355
+ def nearest(key, last: false)
1356
+ n = find_nearest_node(key)
1357
+ return nil if n == @nil_node || n.value.empty?
1358
+ [n.key, last ? n.value.last : n.value.first]
1359
+ end
1296
1360
 
1297
- # Retrieves all values associated with the given key.
1298
- #
1299
- # @param key [Object] the key to look up
1300
- # @return [Array, nil] an Array containing all values, or nil if not found
1301
- # @example
1302
- # tree = MultiRBTree.new
1303
- # tree.insert(1, 'first')
1304
- # tree.insert(1, 'second')
1305
- # tree.get_all(1).to_a # => ["first", "second"]
1306
- def get_all(key)
1307
- n = find_node(key)
1308
- n == @nil_node || n.value.empty? ? nil : n.value
1361
+ def prev(key, last: false)
1362
+ pair = super(key)
1363
+ return nil unless pair
1364
+ [pair[0], last ? pair[1].last : pair[1].first]
1365
+ end
1366
+
1367
+ def succ(key, last: false)
1368
+ pair = super(key)
1369
+ return nil unless pair
1370
+ [pair[0], last ? pair[1].last : pair[1].first]
1309
1371
  end
1310
1372
 
1311
1373
  # Inserts a value for the given key.
@@ -1433,7 +1495,7 @@ class MultiRBTree < RBTree
1433
1495
  node.value.shift
1434
1496
  @size -= 1
1435
1497
  if node.value.empty?
1436
- remove_node(node)
1498
+ delete_node(key)
1437
1499
  end
1438
1500
  [key, val]
1439
1501
  end
@@ -1441,189 +1503,38 @@ class MultiRBTree < RBTree
1441
1503
  def pop
1442
1504
  n = rightmost(@root)
1443
1505
  return nil if n == @nil_node
1506
+ key = n.key
1444
1507
  val = n.value.last
1445
1508
  n.value.pop
1446
1509
  @size -= 1
1447
1510
  if n.value.empty?
1448
- remove_node(n)
1511
+ delete_node(key)
1449
1512
  end
1450
- [n.key, val]
1451
- end
1452
-
1453
- def min(last: false)
1454
- return nil if @min_node == @nil_node || @min_node.value.empty?
1455
- [@min_node.key, last ? @min_node.value.last : @min_node.value.first]
1456
- end
1457
-
1458
- def max(last: false)
1459
- n = rightmost(@root)
1460
- return nil if n == @nil_node || n.value.empty?
1461
- [n.key, last ? n.value.last : n.value.first]
1462
- end
1463
-
1464
- def nearest(key, last: false)
1465
- n = find_nearest_node(key)
1466
- return nil if n == @nil_node || n.value.empty?
1467
- [n.key, last ? n.value.last : n.value.first]
1468
- end
1469
-
1470
- def prev(key, last: false)
1471
- n = find_predecessor_node(key)
1472
- return nil if n == @nil_node || n.value.empty?
1473
- [n.key, last ? n.value.last : n.value.first]
1513
+ [key, val]
1474
1514
  end
1475
1515
 
1476
- def succ(key, last: false)
1477
- n = find_successor_node(key)
1478
- return nil if n == @nil_node || n.value.empty?
1479
- [n.key, last ? n.value.last : n.value.first]
1516
+ # Retrieves all values associated with the given key.
1517
+ #
1518
+ # @param key [Object] the key to look up
1519
+ # @return [Array, nil] an Array containing all values, or nil if not found
1520
+ # @example
1521
+ # tree = MultiRBTree.new
1522
+ # tree.insert(1, 'first')
1523
+ # tree.insert(1, 'second')
1524
+ # tree.get_all(1).to_a # => ["first", "second"]
1525
+ def get_all(key)
1526
+ return enum_for(:get_all, key) unless block_given?
1527
+ @hash_index[key]&.value&.each { |v| yield v }
1480
1528
  end
1481
1529
 
1482
1530
  private
1483
1531
 
1484
- def traverse_asc(node, &block)
1485
- stack = []
1486
- current = node
1487
- while current != @nil_node || !stack.empty?
1488
- while current != @nil_node
1489
- stack << current
1490
- current = current.left
1491
- end
1492
- current = stack.pop
1493
- current.value.each { |v| yield current.key, v }
1494
- current = current.right
1495
- end
1532
+ def traverse_range_asc(...)
1533
+ super { |k, vals| vals.each { |v| yield k, v } }
1496
1534
  end
1497
1535
 
1498
- def traverse_desc(node, &block)
1499
- stack = []
1500
- current = node
1501
- while current != @nil_node || !stack.empty?
1502
- while current != @nil_node
1503
- stack << current
1504
- current = current.right
1505
- end
1506
- current = stack.pop
1507
- current.value.reverse_each { |v| yield current.key, v }
1508
- current = current.left
1509
- end
1510
- end
1511
-
1512
- def traverse_lt(node, key, &block)
1513
- return if node == @nil_node
1514
-
1515
- traverse_lt(node.left, key, &block)
1516
- if (node.key <=> key) < 0
1517
- node.value.each { |v| yield node.key, v }
1518
- traverse_lt(node.right, key, &block)
1519
- end
1520
- end
1521
-
1522
- def traverse_lte(node, key, &block)
1523
- return if node == @nil_node
1524
-
1525
- traverse_lte(node.left, key, &block)
1526
- if (node.key <=> key) <= 0
1527
- node.value.each { |v| yield node.key, v }
1528
- traverse_lte(node.right, key, &block)
1529
- end
1530
- end
1531
-
1532
- def traverse_gt(node, key, &block)
1533
- return if node == @nil_node
1534
-
1535
- if (node.key <=> key) > 0
1536
- traverse_gt(node.left, key, &block)
1537
- node.value.each { |v| yield node.key, v }
1538
- end
1539
- traverse_gt(node.right, key, &block)
1540
- end
1541
-
1542
- def traverse_gte(node, key, &block)
1543
- return if node == @nil_node
1544
-
1545
- if (node.key <=> key) >= 0
1546
- traverse_gte(node.left, key, &block)
1547
- node.value.each { |v| yield node.key, v }
1548
- end
1549
- traverse_gte(node.right, key, &block)
1550
- end
1551
-
1552
- def traverse_between(node, min, max, include_min, include_max, &block)
1553
- return if node == @nil_node
1554
- if (node.key <=> min) > 0
1555
- traverse_between(node.left, min, max, include_min, include_max, &block)
1556
- end
1557
-
1558
- greater = include_min ? (node.key <=> min) >= 0 : (node.key <=> min) > 0
1559
- less = include_max ? (node.key <=> max) <= 0 : (node.key <=> max) < 0
1560
-
1561
- if greater && less
1562
- node.value.each { |v| yield node.key, v }
1563
- end
1564
-
1565
- if (node.key <=> max) < 0
1566
- traverse_between(node.right, min, max, include_min, include_max, &block)
1567
- end
1568
- end
1569
-
1570
- def traverse_lt_desc(node, key, &block)
1571
- return if node == @nil_node
1572
-
1573
- if (node.key <=> key) < 0
1574
- traverse_lt_desc(node.right, key, &block)
1575
- node.value.reverse_each { |v| yield node.key, v }
1576
- end
1577
- traverse_lt_desc(node.left, key, &block)
1578
- end
1579
-
1580
- def traverse_lte_desc(node, key, &block)
1581
- return if node == @nil_node
1582
-
1583
- if (node.key <=> key) <= 0
1584
- traverse_lte_desc(node.right, key, &block)
1585
- node.value.reverse_each { |v| yield node.key, v }
1586
- end
1587
- traverse_lte_desc(node.left, key, &block)
1588
- end
1589
-
1590
- def traverse_gt_desc(node, key, &block)
1591
- return if node == @nil_node
1592
-
1593
- traverse_gt_desc(node.right, key, &block)
1594
- if (node.key <=> key) > 0
1595
- node.value.reverse_each { |v| yield node.key, v }
1596
- traverse_gt_desc(node.left, key, &block)
1597
- end
1598
- end
1599
-
1600
- def traverse_gte_desc(node, key, &block)
1601
- return if node == @nil_node
1602
-
1603
- traverse_gte_desc(node.right, key, &block)
1604
- if (node.key <=> key) >= 0
1605
- node.value.reverse_each { |v| yield node.key, v }
1606
- traverse_gte_desc(node.left, key, &block)
1607
- end
1608
- end
1609
-
1610
- def traverse_between_desc(node, min, max, include_min, include_max, &block)
1611
- return if node == @nil_node
1612
-
1613
- if (node.key <=> max) < 0
1614
- traverse_between_desc(node.right, min, max, include_min, include_max, &block)
1615
- end
1616
-
1617
- greater = include_min ? (node.key <=> min) >= 0 : (node.key <=> min) > 0
1618
- less = include_max ? (node.key <=> max) <= 0 : (node.key <=> max) < 0
1619
-
1620
- if greater && less
1621
- node.value.reverse_each { |v| yield node.key, v }
1622
- end
1623
-
1624
- if (node.key <=> min) > 0
1625
- traverse_between_desc(node.left, min, max, include_min, include_max, &block)
1626
- end
1536
+ def traverse_range_desc(...)
1537
+ super { |k, vals| vals.reverse_each { |v| yield k, v } }
1627
1538
  end
1628
1539
  end
1629
1540
 
@@ -1671,11 +1582,7 @@ class RBTree::Node
1671
1582
  @parent = parent
1672
1583
  end
1673
1584
 
1674
- # Checks if the node is red.
1675
- # @return [Boolean] true if red, false otherwise
1676
- def red? = @color == RED
1677
-
1678
- # Checks if the node is black.
1679
- # @return [Boolean] true if black, false otherwise
1680
- def black? = @color == BLACK
1585
+ # Returns the key-value pair.
1586
+ # @return [Array(Object, Object)] the key-value pair
1587
+ def pair = [key, value]
1681
1588
  end
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.2.0
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Masahito Suzuki