rbtree-ruby 0.2.1 → 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.
Files changed (5) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -0
  3. data/lib/rbtree/version.rb +1 -1
  4. data/lib/rbtree.rb +294 -598
  5. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 89348dfde7177409ecdca6a4184ebee7f83f3a57eebb84b3f4925ad4460a7a92
4
- data.tar.gz: bd46b055e05a121787b67ecf20836181800abe0a230800703872c1412826ccfa
3
+ metadata.gz: 13b088e9f0f8ab5cf80a77b8f9b8e1af73b94b33bdff90115fe575def2c54b11
4
+ data.tar.gz: 51636a7c22c4ccc70d2ac14bafc58a39bbccac7599a704506c280d8d39345117
5
5
  SHA512:
6
- metadata.gz: 908a2d3d58bfac4c7d092e745ebe7f3f2c391551ea5fa7822871d1d0334c64985169df7433342e0e77cad9cf85f8a6b1a265ee427d96445095b3aa27da73d8ef
7
- data.tar.gz: c7b5afe4a5189deee48c6abc5cbca6340c14ebfc65d581f2788117bfb84aabca7757582ab5b6bbcf7cc5866e6350be4f85f87fda78ea49af8c394dd0884de6b3
6
+ metadata.gz: e543801d0b22de4ee8654f7b8164121c2107ccda64bc16f47d034e98526703e4aa444e03cecd225bddb9aa9fc5547813bcd1bc73cd4a4048df98eee5d41a2fc6
7
+ data.tar.gz: 6d6986550fe2293e971558e65119f230c3eb26e8f43f8af77fe8bf666d5df337c6bf23e36a4e4fd7e8aee86287b6f58579e48a637e66d27a6e80ab66b0010ed4
data/CHANGELOG.md CHANGED
@@ -5,6 +5,19 @@ 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
+
8
21
  ## [0.2.1] - 2026-01-14
9
22
 
10
23
  ### Added
@@ -2,5 +2,5 @@
2
2
 
3
3
  class RBTree
4
4
  # The version of the rbtree-ruby gem
5
- VERSION = "0.2.1"
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
@@ -273,6 +315,17 @@ class RBTree
273
315
  result
274
316
  end
275
317
 
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
+
276
329
  # Iterates over all key-value pairs in ascending (or descending) order.
277
330
  #
278
331
  # @param reverse [Boolean] if true, iterate in descending order (default: false)
@@ -296,28 +349,10 @@ class RBTree
296
349
  # end
297
350
  def each(reverse: false, safe: false, &block)
298
351
  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
352
+ if reverse
353
+ traverse_all_desc(@root, safe: safe, &block)
315
354
  else
316
- if reverse
317
- traverse_desc(@root, &block)
318
- else
319
- traverse_asc(@root, &block)
320
- end
355
+ traverse_all_asc(@root, safe: safe, &block)
321
356
  end
322
357
  self
323
358
  end
@@ -343,22 +378,6 @@ class RBTree
343
378
  # @see #each
344
379
  def reverse_each(safe: false, &block) = each(reverse: true, safe: safe, &block)
345
380
 
346
- # Returns the minimum key-value pair without removing it.
347
- #
348
- # @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
349
- # @example
350
- # tree = RBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
351
- # tree.min # => [1, "one"]
352
- def min = find_min
353
-
354
- # Returns the maximum key-value pair without removing it.
355
- #
356
- # @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
357
- # @example
358
- # tree = RBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
359
- # tree.max # => [3, "three"]
360
- def max = find_max
361
-
362
381
  # Retrieves all key-value pairs with keys less than the specified key.
363
382
  #
364
383
  # @param key [Object] the upper bound (exclusive)
@@ -373,26 +392,10 @@ class RBTree
373
392
  # tree.lt(3, safe: true) { |k, _| tree.delete(k) if k.even? } # safe to delete
374
393
  def lt(key, reverse: false, safe: false, &block)
375
394
  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
393
- traverse_lt_desc(@root, key, &block)
395
+ if reverse
396
+ traverse_lt_desc(@root, key, safe: safe, &block)
394
397
  else
395
- traverse_lt(@root, key, &block)
398
+ traverse_lt_asc(@root, key, safe: safe, &block)
396
399
  end
397
400
  self
398
401
  end
@@ -410,26 +413,10 @@ class RBTree
410
413
  # tree.lte(3, reverse: true).first # => [3, "three"]
411
414
  def lte(key, reverse: false, safe: false, &block)
412
415
  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
430
- traverse_lte_desc(@root, key, &block)
416
+ if reverse
417
+ traverse_lte_desc(@root, key, safe: safe, &block)
431
418
  else
432
- traverse_lte(@root, key, &block)
419
+ traverse_lte_asc(@root, key, safe: safe, &block)
433
420
  end
434
421
  self
435
422
  end
@@ -447,26 +434,10 @@ class RBTree
447
434
  # tree.gt(2, reverse: true).first # => [4, "four"]
448
435
  def gt(key, reverse: false, safe: false, &block)
449
436
  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
467
- traverse_gt_desc(@root, key, &block)
437
+ if reverse
438
+ traverse_gt_desc(@root, key, safe: safe, &block)
468
439
  else
469
- traverse_gt(@root, key, &block)
440
+ traverse_gt_asc(@root, key, safe: safe, &block)
470
441
  end
471
442
  self
472
443
  end
@@ -484,26 +455,10 @@ class RBTree
484
455
  # tree.gte(2, reverse: true).first # => [4, "four"]
485
456
  def gte(key, reverse: false, safe: false, &block)
486
457
  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
504
- traverse_gte_desc(@root, key, &block)
458
+ if reverse
459
+ traverse_gte_desc(@root, key, safe: safe, &block)
505
460
  else
506
- traverse_gte(@root, key, &block)
461
+ traverse_gte_asc(@root, key, safe: safe, &block)
507
462
  end
508
463
  self
509
464
  end
@@ -524,82 +479,27 @@ class RBTree
524
479
  # tree.between(2, 4, reverse: true).first # => [4, "four"]
525
480
  def between(min, max, include_min: true, include_max: true, reverse: false, safe: false, &block)
526
481
  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
546
- traverse_between_desc(@root, min, max, include_min, include_max, &block)
482
+ if reverse
483
+ traverse_between_desc(@root, min, max, include_min, include_max, safe: safe, &block)
547
484
  else
548
- traverse_between(@root, min, max, include_min, include_max, &block)
485
+ traverse_between_asc(@root, min, max, include_min, include_max, safe: safe, &block)
549
486
  end
550
487
  self
551
488
  end
552
489
 
553
- # Returns the key-value pair with the key closest to the given key.
554
- #
555
- # This method requires keys to be numeric or support subtraction and abs methods.
556
- # If multiple keys have the same distance, the one with the smaller key is returned.
557
- #
558
- # @param key [Numeric] the target key
559
- # @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
560
- # @example
561
- # tree = RBTree.new({1 => 'one', 5 => 'five', 10 => 'ten'})
562
- # tree.nearest(4) # => [5, "five"]
563
- # tree.nearest(7) # => [5, "five"]
564
- # tree.nearest(8) # => [10, "ten"]
565
- def nearest(key)
566
- return nil unless key.respond_to?(:-)
567
- n = find_nearest_node(key)
568
- n == @nil_node ? nil : n.pair
569
- end
570
-
571
- # Returns the key-value pair with the largest key that is smaller than the given key.
572
- #
573
- # If the key exists in the tree, returns the predecessor (previous element).
574
- # If the key does not exist, returns the largest key-value pair with key < given key.
575
- #
576
- # @param key [Object] the reference key
577
- # @return [Array(Object, Object), nil] a two-element array [key, value], or nil if no predecessor exists
578
- # @example
579
- # tree = RBTree.new({1 => 'one', 3 => 'three', 5 => 'five', 7 => 'seven'})
580
- # tree.prev(5) # => [3, "three"]
581
- # tree.prev(4) # => [3, "three"] (4 does not exist)
582
- # tree.prev(1) # => nil (no predecessor)
583
- def prev(key)
584
- n = find_predecessor_node(key)
585
- n == @nil_node ? nil : n.pair
586
- end
587
-
588
- # Returns the key-value pair with the smallest key that is larger than the given key.
490
+ # Returns a string representation of the tree.
589
491
  #
590
- # If the key exists in the tree, returns the successor (next element).
591
- # 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.
592
493
  #
593
- # @param key [Object] the reference key
594
- # @return [Array(Object, Object), nil] a two-element array [key, value], or nil if no successor exists
595
- # @example
596
- # tree = RBTree.new({1 => 'one', 3 => 'three', 5 => 'five', 7 => 'seven'})
597
- # tree.succ(5) # => [7, "seven"]
598
- # tree.succ(4) # => [5, "five"] (4 does not exist)
599
- # tree.succ(7) # => nil (no successor)
600
- def succ(key)
601
- n = find_successor_node(key)
602
- n == @nil_node ? nil : n.pair
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
603
503
  end
604
504
 
605
505
  # Validates the red-black tree properties.
@@ -618,46 +518,138 @@ class RBTree
618
518
  true
619
519
  end
620
520
 
621
- # @!visibility private
622
- private
623
-
624
- # Traverses the tree in ascending order (in-order traversal).
521
+ # @!visibility private
522
+ private
523
+
524
+ # Traverses the tree in ascending order (in-order traversal).
525
+ #
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
532
+ # @yield [key, value] each key-value pair in ascending order
533
+ # @return [void]
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
577
+ end
578
+ end
579
+ end
580
+
581
+ # Traverses the tree in descending order (reverse in-order traversal).
625
582
  #
626
583
  # @param node [Node] the current node
627
- # @yield [key, value] each key-value pair in ascending order
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
589
+ # @yield [key, value] each key-value pair in descending order
628
590
  # @return [void]
629
- def traverse_asc(node, &block)
630
- stack = []
631
- current = node
632
- while current != @nil_node || !stack.empty?
633
- while current != @nil_node
634
- stack << current
635
- current = current.left
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
636
634
  end
637
- current = stack.pop
638
- yield current.pair
639
- current = current.right
640
635
  end
641
636
  end
642
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
+
643
646
  # Traverses the tree in descending order (reverse in-order traversal).
644
647
  #
645
648
  # @param node [Node] the current node
646
649
  # @yield [key, value] each key-value pair in descending order
647
650
  # @return [void]
648
- def traverse_desc(node, &block)
649
- stack = []
650
- current = node
651
- while current != @nil_node || !stack.empty?
652
- while current != @nil_node
653
- stack << current
654
- current = current.right
655
- end
656
- current = stack.pop
657
- yield current.pair
658
- current = current.left
659
- end
660
- end
651
+ def traverse_all_desc(node, safe: false, &block) =
652
+ traverse_range_desc(node, nil, nil, false, false, safe: safe, &block)
661
653
 
662
654
  # Traverses nodes with keys less than the specified key.
663
655
  #
@@ -665,15 +657,8 @@ class RBTree
665
657
  # @param key [Object] the upper bound (exclusive)
666
658
  # @yield [key, value] each matching key-value pair
667
659
  # @return [void]
668
- def traverse_lt(node, key, &block)
669
- return if node == @nil_node
670
-
671
- traverse_lt(node.left, key, &block)
672
- if (node.key <=> key) < 0
673
- yield node.pair
674
- traverse_lt(node.right, key, &block)
675
- end
676
- end
660
+ def traverse_lt_asc(node, key, safe: false, &block) =
661
+ traverse_range_asc(node, nil, key, false, false, safe: safe, &block)
677
662
 
678
663
  # Traverses nodes with keys less than or equal to the specified key.
679
664
  #
@@ -681,15 +666,8 @@ class RBTree
681
666
  # @param key [Object] the upper bound (inclusive)
682
667
  # @yield [key, value] each matching key-value pair
683
668
  # @return [void]
684
- def traverse_lte(node, key, &block)
685
- return if node == @nil_node
686
-
687
- traverse_lte(node.left, key, &block)
688
- if (node.key <=> key) <= 0
689
- yield node.pair
690
- traverse_lte(node.right, key, &block)
691
- end
692
- end
669
+ def traverse_lte_asc(node, key, safe: false, &block) =
670
+ traverse_range_asc(node, nil, key, false, true, safe: safe, &block)
693
671
 
694
672
  # Traverses nodes with keys greater than the specified key.
695
673
  #
@@ -697,15 +675,8 @@ class RBTree
697
675
  # @param key [Object] the lower bound (exclusive)
698
676
  # @yield [key, value] each matching key-value pair
699
677
  # @return [void]
700
- def traverse_gt(node, key, &block)
701
- return if node == @nil_node
702
-
703
- if (node.key <=> key) > 0
704
- traverse_gt(node.left, key, &block)
705
- yield node.pair
706
- end
707
- traverse_gt(node.right, key, &block)
708
- end
678
+ def traverse_gt_asc(node, key, safe: false, &block) =
679
+ traverse_range_asc(node, key, nil, false, false, safe: safe, &block)
709
680
 
710
681
  # Traverses nodes with keys greater than or equal to the specified key.
711
682
  #
@@ -713,15 +684,8 @@ class RBTree
713
684
  # @param key [Object] the lower bound (inclusive)
714
685
  # @yield [key, value] each matching key-value pair
715
686
  # @return [void]
716
- def traverse_gte(node, key, &block)
717
- return if node == @nil_node
718
-
719
- if (node.key <=> key) >= 0
720
- traverse_gte(node.left, key, &block)
721
- yield node.pair
722
- end
723
- traverse_gte(node.right, key, &block)
724
- end
687
+ def traverse_gte_asc(node, key, safe: false, &block) =
688
+ traverse_range_asc(node, key, nil, true, false, safe: safe, &block)
725
689
 
726
690
  # Traverses nodes with keys within the specified range.
727
691
  #
@@ -732,23 +696,8 @@ class RBTree
732
696
  # @param include_max [Boolean] whether to include the upper bound
733
697
  # @yield [key, value] each matching key-value pair
734
698
  # @return [void]
735
- def traverse_between(node, min, max, include_min, include_max, &block)
736
- return if node == @nil_node
737
- if (node.key <=> min) > 0
738
- traverse_between(node.left, min, max, include_min, include_max, &block)
739
- end
740
-
741
- greater = include_min ? (node.key <=> min) >= 0 : (node.key <=> min) > 0
742
- less = include_max ? (node.key <=> max) <= 0 : (node.key <=> max) < 0
743
-
744
- if greater && less
745
- yield node.pair
746
- end
747
-
748
- if (node.key <=> max) < 0
749
- traverse_between(node.right, min, max, include_min, include_max, &block)
750
- end
751
- 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)
752
701
 
753
702
  # Traverses nodes with keys less than the specified key in descending order.
754
703
  #
@@ -756,15 +705,8 @@ class RBTree
756
705
  # @param key [Object] the upper bound (exclusive)
757
706
  # @yield [key, value] each matching key-value pair in descending order
758
707
  # @return [void]
759
- def traverse_lt_desc(node, key, &block)
760
- return if node == @nil_node
761
-
762
- if (node.key <=> key) < 0
763
- traverse_lt_desc(node.right, key, &block)
764
- yield node.pair
765
- end
766
- traverse_lt_desc(node.left, key, &block)
767
- end
708
+ def traverse_lt_desc(node, key, safe: false, &block) =
709
+ traverse_range_desc(node, nil, key, false, false, safe: safe, &block)
768
710
 
769
711
  # Traverses nodes with keys less than or equal to the specified key in descending order.
770
712
  #
@@ -772,15 +714,8 @@ class RBTree
772
714
  # @param key [Object] the upper bound (inclusive)
773
715
  # @yield [key, value] each matching key-value pair in descending order
774
716
  # @return [void]
775
- def traverse_lte_desc(node, key, &block)
776
- return if node == @nil_node
777
-
778
- if (node.key <=> key) <= 0
779
- traverse_lte_desc(node.right, key, &block)
780
- yield node.pair
781
- end
782
- traverse_lte_desc(node.left, key, &block)
783
- end
717
+ def traverse_lte_desc(node, key, safe: false, &block) =
718
+ traverse_range_desc(node, nil, key, false, true, safe: safe, &block)
784
719
 
785
720
  # Traverses nodes with keys greater than the specified key in descending order.
786
721
  #
@@ -788,15 +723,8 @@ class RBTree
788
723
  # @param key [Object] the lower bound (exclusive)
789
724
  # @yield [key, value] each matching key-value pair in descending order
790
725
  # @return [void]
791
- def traverse_gt_desc(node, key, &block)
792
- return if node == @nil_node
793
-
794
- traverse_gt_desc(node.right, key, &block)
795
- if (node.key <=> key) > 0
796
- yield node.pair
797
- traverse_gt_desc(node.left, key, &block)
798
- end
799
- end
726
+ def traverse_gt_desc(node, key, safe: false, &block) =
727
+ traverse_range_desc(node, key, nil, false, false, safe: safe, &block)
800
728
 
801
729
  # Traverses nodes with keys greater than or equal to the specified key in descending order.
802
730
  #
@@ -804,15 +732,8 @@ class RBTree
804
732
  # @param key [Object] the lower bound (inclusive)
805
733
  # @yield [key, value] each matching key-value pair in descending order
806
734
  # @return [void]
807
- def traverse_gte_desc(node, key, &block)
808
- return if node == @nil_node
809
-
810
- traverse_gte_desc(node.right, key, &block)
811
- if (node.key <=> key) >= 0
812
- yield node.pair
813
- traverse_gte_desc(node.left, key, &block)
814
- end
815
- end
735
+ def traverse_gte_desc(node, key, safe: false, &block) =
736
+ traverse_range_desc(node, key, nil, true, false, safe: safe, &block)
816
737
 
817
738
  # Traverses nodes with keys within the specified range in descending order.
818
739
  #
@@ -823,24 +744,8 @@ class RBTree
823
744
  # @param include_max [Boolean] whether to include the upper bound
824
745
  # @yield [key, value] each matching key-value pair in descending order
825
746
  # @return [void]
826
- def traverse_between_desc(node, min, max, include_min, include_max, &block)
827
- return if node == @nil_node
828
-
829
- if (node.key <=> max) < 0
830
- traverse_between_desc(node.right, min, max, include_min, include_max, &block)
831
- end
832
-
833
- greater = include_min ? (node.key <=> min) >= 0 : (node.key <=> min) > 0
834
- less = include_max ? (node.key <=> max) <= 0 : (node.key <=> max) < 0
835
-
836
- if greater && less
837
- yield node.pair
838
- end
839
-
840
- if (node.key <=> min) > 0
841
- traverse_between_desc(node.left, min, max, include_min, include_max, &block)
842
- end
843
- 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)
844
749
 
845
750
  # Restores red-black tree properties after insertion.
846
751
  #
@@ -1407,6 +1312,17 @@ end
1407
1312
  # @author Masahito Suzuki
1408
1313
  # @since 0.1.2
1409
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
+
1410
1326
  # Retrieves a value associated with the given key.
1411
1327
  #
1412
1328
  # @param key [Object] the key to look up
@@ -1436,26 +1352,22 @@ class MultiRBTree < RBTree
1436
1352
  # @return [Object, nil] the last value for the key, or nil if not found
1437
1353
  def get_last(key) = get(key, last: true)
1438
1354
 
1439
- # Returns the first value for the given key (for Hash-like access).
1440
- #
1441
- # Note: Unlike get(), this method does not accept options.
1442
- #
1443
- # @param key [Object] the key to look up
1444
- # @return [Object, nil] the first value for the key, or nil if not found
1445
- 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
1446
1360
 
1447
- # Retrieves all values associated with the given key.
1448
- #
1449
- # @param key [Object] the key to look up
1450
- # @return [Array, nil] an Array containing all values, or nil if not found
1451
- # @example
1452
- # tree = MultiRBTree.new
1453
- # tree.insert(1, 'first')
1454
- # tree.insert(1, 'second')
1455
- # tree.get_all(1).to_a # => ["first", "second"]
1456
- def get_all(key)
1457
- return enum_for(:get_all, key) unless block_given?
1458
- @hash_index[key]&.value&.each { |v| yield v }
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]
1459
1371
  end
1460
1372
 
1461
1373
  # Inserts a value for the given key.
@@ -1583,7 +1495,7 @@ class MultiRBTree < RBTree
1583
1495
  node.value.shift
1584
1496
  @size -= 1
1585
1497
  if node.value.empty?
1586
- remove_node(node)
1498
+ delete_node(key)
1587
1499
  end
1588
1500
  [key, val]
1589
1501
  end
@@ -1591,246 +1503,38 @@ class MultiRBTree < RBTree
1591
1503
  def pop
1592
1504
  n = rightmost(@root)
1593
1505
  return nil if n == @nil_node
1506
+ key = n.key
1594
1507
  val = n.value.last
1595
1508
  n.value.pop
1596
1509
  @size -= 1
1597
1510
  if n.value.empty?
1598
- remove_node(n)
1599
- end
1600
- [n.key, val]
1601
- end
1602
-
1603
- def min(last: false)
1604
- return nil if @min_node == @nil_node || @min_node.value.empty?
1605
- [@min_node.key, last ? @min_node.value.last : @min_node.value.first]
1606
- end
1607
-
1608
- def max(last: false)
1609
- n = rightmost(@root)
1610
- return nil if n == @nil_node || n.value.empty?
1611
- [n.key, last ? n.value.last : n.value.first]
1612
- end
1613
-
1614
- def nearest(key, last: false)
1615
- n = find_nearest_node(key)
1616
- return nil if n == @nil_node || n.value.empty?
1617
- [n.key, last ? n.value.last : n.value.first]
1618
- end
1619
-
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
1629
- end
1630
-
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
1640
- end
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
1511
+ delete_node(key)
1672
1512
  end
1513
+ [key, val]
1673
1514
  end
1674
1515
 
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
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 }
1684
1528
  end
1685
1529
 
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
-
1689
1530
  private
1690
1531
 
1691
- def traverse_asc(node, &block)
1692
- stack = []
1693
- current = node
1694
- while current != @nil_node || !stack.empty?
1695
- while current != @nil_node
1696
- stack << current
1697
- current = current.left
1698
- end
1699
- current = stack.pop
1700
- current.value.each { |v| yield current.key, v }
1701
- current = current.right
1702
- end
1703
- end
1704
-
1705
- def traverse_desc(node, &block)
1706
- stack = []
1707
- current = node
1708
- while current != @nil_node || !stack.empty?
1709
- while current != @nil_node
1710
- stack << current
1711
- current = current.right
1712
- end
1713
- current = stack.pop
1714
- current.value.reverse_each { |v| yield current.key, v }
1715
- current = current.left
1716
- end
1717
- end
1718
-
1719
- def traverse_lt(node, key, &block)
1720
- return if node == @nil_node
1721
-
1722
- traverse_lt(node.left, key, &block)
1723
- if (node.key <=> key) < 0
1724
- node.value.each { |v| yield node.key, v }
1725
- traverse_lt(node.right, key, &block)
1726
- end
1727
- end
1728
-
1729
- def traverse_lte(node, key, &block)
1730
- return if node == @nil_node
1731
-
1732
- traverse_lte(node.left, key, &block)
1733
- if (node.key <=> key) <= 0
1734
- node.value.each { |v| yield node.key, v }
1735
- traverse_lte(node.right, key, &block)
1736
- end
1737
- end
1738
-
1739
- def traverse_gt(node, key, &block)
1740
- return if node == @nil_node
1741
-
1742
- if (node.key <=> key) > 0
1743
- traverse_gt(node.left, key, &block)
1744
- node.value.each { |v| yield node.key, v }
1745
- end
1746
- traverse_gt(node.right, key, &block)
1747
- end
1748
-
1749
- def traverse_gte(node, key, &block)
1750
- return if node == @nil_node
1751
-
1752
- if (node.key <=> key) >= 0
1753
- traverse_gte(node.left, key, &block)
1754
- node.value.each { |v| yield node.key, v }
1755
- end
1756
- traverse_gte(node.right, key, &block)
1757
- end
1758
-
1759
- def traverse_between(node, min, max, include_min, include_max, &block)
1760
- return if node == @nil_node
1761
- if (node.key <=> min) > 0
1762
- traverse_between(node.left, min, max, include_min, include_max, &block)
1763
- end
1764
-
1765
- greater = include_min ? (node.key <=> min) >= 0 : (node.key <=> min) > 0
1766
- less = include_max ? (node.key <=> max) <= 0 : (node.key <=> max) < 0
1767
-
1768
- if greater && less
1769
- node.value.each { |v| yield node.key, v }
1770
- end
1771
-
1772
- if (node.key <=> max) < 0
1773
- traverse_between(node.right, min, max, include_min, include_max, &block)
1774
- end
1775
- end
1776
-
1777
- def traverse_lt_desc(node, key, &block)
1778
- return if node == @nil_node
1779
-
1780
- if (node.key <=> key) < 0
1781
- traverse_lt_desc(node.right, key, &block)
1782
- node.value.reverse_each { |v| yield node.key, v }
1783
- end
1784
- traverse_lt_desc(node.left, key, &block)
1785
- end
1786
-
1787
- def traverse_lte_desc(node, key, &block)
1788
- return if node == @nil_node
1789
-
1790
- if (node.key <=> key) <= 0
1791
- traverse_lte_desc(node.right, key, &block)
1792
- node.value.reverse_each { |v| yield node.key, v }
1793
- end
1794
- traverse_lte_desc(node.left, key, &block)
1795
- end
1796
-
1797
- def traverse_gt_desc(node, key, &block)
1798
- return if node == @nil_node
1799
-
1800
- traverse_gt_desc(node.right, key, &block)
1801
- if (node.key <=> key) > 0
1802
- node.value.reverse_each { |v| yield node.key, v }
1803
- traverse_gt_desc(node.left, key, &block)
1804
- end
1805
- end
1806
-
1807
- def traverse_gte_desc(node, key, &block)
1808
- return if node == @nil_node
1809
-
1810
- traverse_gte_desc(node.right, key, &block)
1811
- if (node.key <=> key) >= 0
1812
- node.value.reverse_each { |v| yield node.key, v }
1813
- traverse_gte_desc(node.left, key, &block)
1814
- end
1532
+ def traverse_range_asc(...)
1533
+ super { |k, vals| vals.each { |v| yield k, v } }
1815
1534
  end
1816
1535
 
1817
- def traverse_between_desc(node, min, max, include_min, include_max, &block)
1818
- return if node == @nil_node
1819
-
1820
- if (node.key <=> max) < 0
1821
- traverse_between_desc(node.right, min, max, include_min, include_max, &block)
1822
- end
1823
-
1824
- greater = include_min ? (node.key <=> min) >= 0 : (node.key <=> min) > 0
1825
- less = include_max ? (node.key <=> max) <= 0 : (node.key <=> max) < 0
1826
-
1827
- if greater && less
1828
- node.value.reverse_each { |v| yield node.key, v }
1829
- end
1830
-
1831
- if (node.key <=> min) > 0
1832
- traverse_between_desc(node.left, min, max, include_min, include_max, &block)
1833
- end
1536
+ def traverse_range_desc(...)
1537
+ super { |k, vals| vals.reverse_each { |v| yield k, v } }
1834
1538
  end
1835
1539
  end
1836
1540
 
@@ -1878,14 +1582,6 @@ class RBTree::Node
1878
1582
  @parent = parent
1879
1583
  end
1880
1584
 
1881
- # Checks if the node is red.
1882
- # @return [Boolean] true if red, false otherwise
1883
- def red? = @color == RED
1884
-
1885
- # Checks if the node is black.
1886
- # @return [Boolean] true if black, false otherwise
1887
- def black? = @color == BLACK
1888
-
1889
1585
  # Returns the key-value pair.
1890
1586
  # @return [Array(Object, Object)] the key-value pair
1891
1587
  def pair = [key, value]
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.1
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Masahito Suzuki