rbtree-ruby 0.2.3 → 0.3.0

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.
data/lib/rbtree.old.rb ADDED
@@ -0,0 +1,1588 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "rbtree/version"
4
+
5
+ # A Red-Black Tree implementation providing efficient ordered key-value storage.
6
+ #
7
+ # RBTree is a self-balancing binary search tree that maintains sorted order of keys
8
+ # and provides O(log n) time complexity for insertion, deletion, and lookup operations.
9
+ # The tree enforces the following red-black properties to maintain balance:
10
+ #
11
+ # 1. Every node is either red or black
12
+ # 2. The root is always black
13
+ # 3. All leaves (nil nodes) are black
14
+ # 4. Red nodes cannot have red children
15
+ # 5. All paths from root to leaves contain the same number of black nodes
16
+ #
17
+ # == Features
18
+ #
19
+ # * Ordered iteration over key-value pairs
20
+ # * Range queries (less than, greater than, between)
21
+ # * Efficient min/max retrieval
22
+ # * Nearest key search for numeric keys
23
+ # * Tree integrity validation
24
+ #
25
+ # == Usage
26
+ #
27
+ # # Create an empty tree
28
+ # tree = RBTree.new
29
+ #
30
+ # # Create from a hash
31
+ # tree = RBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
32
+ #
33
+ # # Create from an array of key-value pairs
34
+ # tree = RBTree.new([[3, 'three'], [1, 'one'], [2, 'two']])
35
+ #
36
+ # # Create using bracket notation
37
+ # tree = RBTree[3 => 'three', 1 => 'one', 2 => 'two']
38
+ #
39
+ # # Insert and retrieve values
40
+ # tree.insert(5, 'five')
41
+ # tree[4] = 'four'
42
+ # puts tree[4] # => "four"
43
+ #
44
+ # # Iterate in sorted order
45
+ # tree.each { |key, value| puts "#{key}: #{value}" }
46
+ #
47
+ # == Performance
48
+ #
49
+ # All major operations (insert, delete, search) run in O(log n) time.
50
+ # Iteration over all elements takes O(n) time.
51
+ #
52
+ # @author Masahito Suzuki
53
+ # @since 0.1.0
54
+ class RBTree
55
+ include Enumerable
56
+
57
+ # Returns the number of key-value pairs stored in the tree.
58
+ # @return [Integer] the number of entries in the tree
59
+ attr_reader :size
60
+
61
+ # Creates a new RBTree from the given arguments.
62
+ #
63
+ # This is a convenience method equivalent to RBTree.new(*args).
64
+ #
65
+ # @param args [Hash, Array] optional initial data
66
+ # @return [RBTree] a new RBTree instance
67
+ # @example
68
+ # tree = RBTree[1 => 'one', 2 => 'two', 3 => 'three']
69
+ def self.[](*args)
70
+ new(*args)
71
+ end
72
+
73
+ # Initializes a new RBTree.
74
+ #
75
+ # The tree can be initialized empty or populated with initial data from a Hash or Array.
76
+ #
77
+ # @param args [Hash, Array, nil] optional initial data
78
+ # - If a Hash is provided, each key-value pair is inserted into the tree
79
+ # - If an Array is provided, it should contain [key, value] pairs
80
+ # - If no arguments are provided, an empty tree is created
81
+ # @raise [ArgumentError] if arguments are invalid
82
+ # @example Create an empty tree
83
+ # tree = RBTree.new
84
+ # @example Create from a hash
85
+ # tree = RBTree.new({1 => 'one', 2 => 'two'})
86
+ # @example Create from an array
87
+ # tree = RBTree.new([[1, 'one'], [2, 'two']])
88
+ def initialize(*args)
89
+ @nil_node = Node.new
90
+ @nil_node.color = Node::BLACK
91
+ @nil_node.left = @nil_node
92
+ @nil_node.right = @nil_node
93
+ @root = @nil_node
94
+ @min_node = @nil_node
95
+ @hash_index = {} # Hash index for O(1) key lookup
96
+ @node_pool = [] # Memory pool for recycling nodes
97
+ @size = 0
98
+
99
+ if args.any?
100
+ source = args.size == 1 ? args.first : args
101
+ case source
102
+ when Hash
103
+ source.each { |k, v| insert(k, v) }
104
+ when Array
105
+ source.each do |arg|
106
+ key, value = arg
107
+ insert(key, value)
108
+ end
109
+ else
110
+ raise ArgumentError, "Invalid arguments"
111
+ end
112
+ end
113
+ end
114
+
115
+ # Checks if the tree is empty.
116
+ #
117
+ # @return [Boolean] true if the tree contains no elements, false otherwise
118
+ def empty? = @root == @nil_node
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
+
136
+ # Checks if the tree contains the given key.
137
+ #
138
+ # @param key [Object] the key to search for
139
+ # @return [Boolean] true if the key exists in the tree, false otherwise
140
+ # @example
141
+ # tree = RBTree.new({1 => 'one', 2 => 'two'})
142
+ # tree.has_key?(1) # => true
143
+ # tree.has_key?(3) # => false
144
+ def has_key?(key)
145
+ @hash_index.key?(key)
146
+ end
147
+
148
+ # Retrieves the value associated with the given key.
149
+ #
150
+ # @param key [Object] the key to look up
151
+ # @return [Object, nil] the associated value, or nil if the key is not found
152
+ # @example
153
+ # tree = RBTree.new({1 => 'one', 2 => 'two'})
154
+ # tree.get(1) # => "one"
155
+ # tree[2] # => "two"
156
+ # tree[3] # => nil
157
+ def get(key)
158
+ @hash_index[key]&.value
159
+ end
160
+ alias_method :[], :get
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
+
214
+ # Inserts or updates a key-value pair in the tree.
215
+ #
216
+ # If the key already exists and overwrite is true (default), the value is updated.
217
+ # If overwrite is false and the key exists, the operation returns nil without modification.
218
+ #
219
+ # @param key [Object] the key to insert (must implement <=>)
220
+ # @param value [Object] the value to associate with the key
221
+ # @param overwrite [Boolean] whether to overwrite existing keys (default: true)
222
+ # @return [Boolean, nil] true if inserted/updated, nil if key exists and overwrite is false
223
+ # @example
224
+ # tree = RBTree.new
225
+ # tree.insert(1, 'one') # => true
226
+ # tree.insert(1, 'ONE') # => true (overwrites)
227
+ # tree.insert(1, 'uno', overwrite: false) # => nil (no change)
228
+ # tree[2] = 'two' # using alias
229
+ def insert(key, value, overwrite: true)
230
+ if (node = @hash_index[key])
231
+ return nil unless overwrite
232
+ node.value = value
233
+ return true
234
+ end
235
+ y = @nil_node
236
+ x = @root
237
+ while x != @nil_node
238
+ y = x
239
+ cmp = key <=> x.key
240
+ if cmp == 0
241
+ return nil unless overwrite
242
+ x.value = value
243
+ return true
244
+ elsif cmp < 0
245
+ x = x.left
246
+ else
247
+ x = x.right
248
+ end
249
+ end
250
+ z = allocate_node(key, value, Node::RED, @nil_node, @nil_node, @nil_node)
251
+ z.parent = y
252
+ if y == @nil_node
253
+ @root = z
254
+ elsif (key <=> y.key) < 0
255
+ y.left = z
256
+ else
257
+ y.right = z
258
+ end
259
+ z.left = @nil_node
260
+ z.right = @nil_node
261
+ z.color = Node::RED
262
+ insert_fixup(z)
263
+ @size += 1
264
+
265
+ if @min_node == @nil_node || (key <=> @min_node.key) < 0
266
+ @min_node = z
267
+ end
268
+
269
+ @hash_index[key] = z # Add to hash index
270
+ true
271
+ end
272
+ alias_method :[]=, :insert
273
+
274
+ # Deletes the key-value pair with the specified key.
275
+ #
276
+ # @param key [Object] the key to delete
277
+ # @return [Object, nil] the value associated with the deleted key, or nil if not found
278
+ # @example
279
+ # tree = RBTree.new({1 => 'one', 2 => 'two'})
280
+ # tree.delete(1) # => "one"
281
+ # tree.delete(3) # => nil
282
+ def delete(key)
283
+ value = delete_node(key)
284
+ return nil unless value
285
+ @size -= 1
286
+ value
287
+ end
288
+
289
+ # Removes and returns the minimum key-value pair.
290
+ #
291
+ # @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
292
+ # @example
293
+ # tree = RBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
294
+ # tree.shift # => [1, "one"]
295
+ # tree.shift # => [2, "two"]
296
+ def shift
297
+ return nil if @min_node == @nil_node
298
+ result = [@min_node.key, @min_node.value]
299
+ delete(@min_node.key)
300
+ result
301
+ end
302
+
303
+ # Removes and returns the maximum key-value pair.
304
+ #
305
+ # @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
306
+ # @example
307
+ # tree = RBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
308
+ # tree.pop # => [3, "three"]
309
+ # tree.pop # => [2, "two"]
310
+ def pop
311
+ n = rightmost(@root)
312
+ return nil if n == @nil_node
313
+ result = n.pair
314
+ delete(n.key)
315
+ result
316
+ end
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
+
329
+ # Iterates over all key-value pairs in ascending (or descending) order.
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)
333
+ # @yield [key, value] each key-value pair in the tree
334
+ # @return [Enumerator, RBTree] an Enumerator if no block is given, self otherwise
335
+ # @example
336
+ # tree = RBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
337
+ # tree.each { |k, v| puts "#{k}: #{v}" }
338
+ # # Output:
339
+ # # 1: one
340
+ # # 2: two
341
+ # # 3: three
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
358
+ end
359
+
360
+ # Iterates over all key-value pairs in descending order of keys.
361
+ #
362
+ # @yield [key, value] each key-value pair in the tree
363
+ # @return [Enumerator, RBTree] an Enumerator if no block is given, self otherwise
364
+ # @example
365
+ # tree = RBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
366
+ # tree.reverse_each { |k, v| puts "#{k}: #{v}" }
367
+ # # Output:
368
+ # # 3: three
369
+ # # 2: two
370
+ # # 1: one
371
+ # Iterates over all key-value pairs in descending order of keys.
372
+ #
373
+ # This is an alias for `each(reverse: true)`.
374
+ #
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)
380
+
381
+ # Retrieves all key-value pairs with keys less than the specified key.
382
+ #
383
+ # @param key [Object] the upper bound (exclusive)
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)
386
+ # @yield [key, value] each matching key-value pair (if block given)
387
+ # @return [Enumerator, RBTree] Enumerator if no block given, self otherwise
388
+ # @example
389
+ # tree = RBTree.new({1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four'})
390
+ # tree.lt(3).to_a # => [[1, "one"], [2, "two"]]
391
+ # tree.lt(3, reverse: true).first # => [2, "two"]
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?
395
+ if reverse
396
+ traverse_lt_desc(@root, key, safe: safe, &block)
397
+ else
398
+ traverse_lt_asc(@root, key, safe: safe, &block)
399
+ end
400
+ self
401
+ end
402
+
403
+ # Retrieves all key-value pairs with keys less than or equal to the specified key.
404
+ #
405
+ # @param key [Object] the upper bound (inclusive)
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)
408
+ # @yield [key, value] each matching key-value pair (if block given)
409
+ # @return [Enumerator, RBTree] Enumerator if no block given, self otherwise
410
+ # @example
411
+ # tree = RBTree.new({1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four'})
412
+ # tree.lte(3).to_a # => [[1, "one"], [2, "two"], [3, "three"]]
413
+ # tree.lte(3, reverse: true).first # => [3, "three"]
414
+ def lte(key, reverse: false, safe: false, &block)
415
+ return enum_for(:lte, key, reverse: reverse, safe: safe) unless block_given?
416
+ if reverse
417
+ traverse_lte_desc(@root, key, safe: safe, &block)
418
+ else
419
+ traverse_lte_asc(@root, key, safe: safe, &block)
420
+ end
421
+ self
422
+ end
423
+
424
+ # Retrieves all key-value pairs with keys greater than the specified key.
425
+ #
426
+ # @param key [Object] the lower bound (exclusive)
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)
429
+ # @yield [key, value] each matching key-value pair (if block given)
430
+ # @return [Enumerator, RBTree] Enumerator if no block given, self otherwise
431
+ # @example
432
+ # tree = RBTree.new({1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four'})
433
+ # tree.gt(2).to_a # => [[3, "three"], [4, "four"]]
434
+ # tree.gt(2, reverse: true).first # => [4, "four"]
435
+ def gt(key, reverse: false, safe: false, &block)
436
+ return enum_for(:gt, key, reverse: reverse, safe: safe) unless block_given?
437
+ if reverse
438
+ traverse_gt_desc(@root, key, safe: safe, &block)
439
+ else
440
+ traverse_gt_asc(@root, key, safe: safe, &block)
441
+ end
442
+ self
443
+ end
444
+
445
+ # Retrieves all key-value pairs with keys greater than or equal to the specified key.
446
+ #
447
+ # @param key [Object] the lower bound (inclusive)
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)
450
+ # @yield [key, value] each matching key-value pair (if block given)
451
+ # @return [Enumerator, RBTree] Enumerator if no block given, self otherwise
452
+ # @example
453
+ # tree = RBTree.new({1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four'})
454
+ # tree.gte(2).to_a # => [[2, "two"], [3, "three"], [4, "four"]]
455
+ # tree.gte(2, reverse: true).first # => [4, "four"]
456
+ def gte(key, reverse: false, safe: false, &block)
457
+ return enum_for(:gte, key, reverse: reverse, safe: safe) unless block_given?
458
+ if reverse
459
+ traverse_gte_desc(@root, key, safe: safe, &block)
460
+ else
461
+ traverse_gte_asc(@root, key, safe: safe, &block)
462
+ end
463
+ self
464
+ end
465
+
466
+ # Retrieves all key-value pairs with keys within the specified range.
467
+ #
468
+ # @param min [Object] the lower bound
469
+ # @param max [Object] the upper bound
470
+ # @param include_min [Boolean] whether to include the lower bound (default: true)
471
+ # @param include_max [Boolean] whether to include the upper bound (default: true)
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)
474
+ # @yield [key, value] each matching key-value pair (if block given)
475
+ # @return [Enumerator, RBTree] Enumerator if no block given, self otherwise
476
+ # @example
477
+ # tree = RBTree.new({1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four', 5 => 'five'})
478
+ # tree.between(2, 4).to_a # => [[2, "two"], [3, "three"], [4, "four"]]
479
+ # tree.between(2, 4, reverse: true).first # => [4, "four"]
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?
482
+ if reverse
483
+ traverse_between_desc(@root, min, max, include_min, include_max, safe: safe, &block)
484
+ else
485
+ traverse_between_asc(@root, min, max, include_min, include_max, safe: safe, &block)
486
+ end
487
+ self
488
+ end
489
+
490
+ # Returns a string representation of the tree.
491
+ #
492
+ # Shows the first 5 entries and total size. Useful for debugging.
493
+ #
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
503
+ end
504
+
505
+ # Validates the red-black tree properties.
506
+ #
507
+ # Checks that:
508
+ # 1. Root is black
509
+ # 2. All paths from root to leaves have the same number of black nodes
510
+ # 3. No red node has a red child
511
+ # 4. Keys are properly ordered
512
+ #
513
+ # @return [Boolean] true if all properties are satisfied, false otherwise
514
+ def valid?
515
+ return false if @root.color == Node::RED
516
+ return false if check_black_height(@root) == -1
517
+ return false unless check_order(@root)
518
+ true
519
+ end
520
+
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).
582
+ #
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
589
+ # @yield [key, value] each key-value pair in descending order
590
+ # @return [void]
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
634
+ end
635
+ end
636
+ end
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
+
654
+ # Traverses nodes with keys less than the specified key.
655
+ #
656
+ # @param node [Node] the current node
657
+ # @param key [Object] the upper bound (exclusive)
658
+ # @yield [key, value] each matching key-value pair
659
+ # @return [void]
660
+ def traverse_lt_asc(node, key, safe: false, &block) =
661
+ traverse_range_asc(node, nil, key, false, false, safe: safe, &block)
662
+
663
+ # Traverses nodes with keys less than or equal to the specified key.
664
+ #
665
+ # @param node [Node] the current node
666
+ # @param key [Object] the upper bound (inclusive)
667
+ # @yield [key, value] each matching key-value pair
668
+ # @return [void]
669
+ def traverse_lte_asc(node, key, safe: false, &block) =
670
+ traverse_range_asc(node, nil, key, false, true, safe: safe, &block)
671
+
672
+ # Traverses nodes with keys greater than the specified key.
673
+ #
674
+ # @param node [Node] the current node
675
+ # @param key [Object] the lower bound (exclusive)
676
+ # @yield [key, value] each matching key-value pair
677
+ # @return [void]
678
+ def traverse_gt_asc(node, key, safe: false, &block) =
679
+ traverse_range_asc(node, key, nil, false, false, safe: safe, &block)
680
+
681
+ # Traverses nodes with keys greater than or equal to the specified key.
682
+ #
683
+ # @param node [Node] the current node
684
+ # @param key [Object] the lower bound (inclusive)
685
+ # @yield [key, value] each matching key-value pair
686
+ # @return [void]
687
+ def traverse_gte_asc(node, key, safe: false, &block) =
688
+ traverse_range_asc(node, key, nil, true, false, safe: safe, &block)
689
+
690
+ # Traverses nodes with keys within the specified range.
691
+ #
692
+ # @param node [Node] the current node
693
+ # @param min [Object] the lower bound
694
+ # @param max [Object] the upper bound
695
+ # @param include_min [Boolean] whether to include the lower bound
696
+ # @param include_max [Boolean] whether to include the upper bound
697
+ # @yield [key, value] each matching key-value pair
698
+ # @return [void]
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)
701
+
702
+ # Traverses nodes with keys less than the specified key in descending order.
703
+ #
704
+ # @param node [Node] the current node
705
+ # @param key [Object] the upper bound (exclusive)
706
+ # @yield [key, value] each matching key-value pair in descending order
707
+ # @return [void]
708
+ def traverse_lt_desc(node, key, safe: false, &block) =
709
+ traverse_range_desc(node, nil, key, false, false, safe: safe, &block)
710
+
711
+ # Traverses nodes with keys less than or equal to the specified key in descending order.
712
+ #
713
+ # @param node [Node] the current node
714
+ # @param key [Object] the upper bound (inclusive)
715
+ # @yield [key, value] each matching key-value pair in descending order
716
+ # @return [void]
717
+ def traverse_lte_desc(node, key, safe: false, &block) =
718
+ traverse_range_desc(node, nil, key, false, true, safe: safe, &block)
719
+
720
+ # Traverses nodes with keys greater than the specified key in descending order.
721
+ #
722
+ # @param node [Node] the current node
723
+ # @param key [Object] the lower bound (exclusive)
724
+ # @yield [key, value] each matching key-value pair in descending order
725
+ # @return [void]
726
+ def traverse_gt_desc(node, key, safe: false, &block) =
727
+ traverse_range_desc(node, key, nil, false, false, safe: safe, &block)
728
+
729
+ # Traverses nodes with keys greater than or equal to the specified key in descending order.
730
+ #
731
+ # @param node [Node] the current node
732
+ # @param key [Object] the lower bound (inclusive)
733
+ # @yield [key, value] each matching key-value pair in descending order
734
+ # @return [void]
735
+ def traverse_gte_desc(node, key, safe: false, &block) =
736
+ traverse_range_desc(node, key, nil, true, false, safe: safe, &block)
737
+
738
+ # Traverses nodes with keys within the specified range in descending order.
739
+ #
740
+ # @param node [Node] the current node
741
+ # @param min [Object] the lower bound
742
+ # @param max [Object] the upper bound
743
+ # @param include_min [Boolean] whether to include the lower bound
744
+ # @param include_max [Boolean] whether to include the upper bound
745
+ # @yield [key, value] each matching key-value pair in descending order
746
+ # @return [void]
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)
749
+
750
+ # Restores red-black tree properties after insertion.
751
+ #
752
+ # This method fixes any violations of red-black properties that may occur
753
+ # after inserting a new node (which is always colored red).
754
+ #
755
+ # @param z [Node] the newly inserted node
756
+ # @return [void]
757
+ def insert_fixup(z)
758
+ while z.parent.color == Node::RED
759
+ if z.parent == z.parent.parent.left
760
+ y = z.parent.parent.right
761
+ if y.color == Node::RED
762
+ z.parent.color = Node::BLACK
763
+ y.color = Node::BLACK
764
+ z.parent.parent.color = Node::RED
765
+ z = z.parent.parent
766
+ else
767
+ if z == z.parent.right
768
+ z = z.parent
769
+ left_rotate(z)
770
+ end
771
+ z.parent.color = Node::BLACK
772
+ z.parent.parent.color = Node::RED
773
+ right_rotate(z.parent.parent)
774
+ end
775
+ else
776
+ y = z.parent.parent.left
777
+ if y.color == Node::RED
778
+ z.parent.color = Node::BLACK
779
+ y.color = Node::BLACK
780
+ z.parent.parent.color = Node::RED
781
+ z = z.parent.parent
782
+ else
783
+ if z == z.parent.left
784
+ z = z.parent
785
+ right_rotate(z)
786
+ end
787
+ z.parent.color = Node::BLACK
788
+ z.parent.parent.color = Node::RED
789
+ left_rotate(z.parent.parent)
790
+ end
791
+ end
792
+ end
793
+ @root.color = Node::BLACK
794
+ end
795
+
796
+ # Finds and removes a node by key, returning its value.
797
+ #
798
+ # @param key [Object] the key to delete
799
+ # @return [Object, nil] the value of the deleted node, or nil if not found
800
+ def delete_node(key)
801
+ z = @hash_index.delete(key) # O(1) lookup and remove from index
802
+ return nil unless z
803
+ remove_node(z)
804
+ end
805
+
806
+ # Removes a node from the tree and restores red-black properties.
807
+ #
808
+ # Handles three cases:
809
+ # 1. Node has no left child
810
+ # 2. Node has no right child
811
+ # 3. Node has both children (replace with inorder successor)
812
+ #
813
+ # @param z [Node] the node to remove
814
+ # @return [Object] the value of the removed node
815
+ def remove_node(z)
816
+ next_min_node = nil
817
+ if z == @min_node
818
+ if z.right != @nil_node
819
+ next_min_node = leftmost(z.right)
820
+ else
821
+ next_min_node = z.parent
822
+ end
823
+ end
824
+
825
+ y = z
826
+ y_original_color = y.color
827
+ if z.left == @nil_node
828
+ x = z.right
829
+ transplant(z, z.right)
830
+ elsif z.right == @nil_node
831
+ x = z.left
832
+ transplant(z, z.left)
833
+ else
834
+ y = leftmost(z.right)
835
+ y_original_color = y.color
836
+ x = y.right
837
+ if y.parent == z
838
+ x.parent = y
839
+ else
840
+ transplant(y, y.right)
841
+ y.right = z.right
842
+ y.right.parent = y
843
+ end
844
+ transplant(z, y)
845
+ y.left = z.left
846
+ y.left.parent = y
847
+ y.color = z.color
848
+ end
849
+ if y_original_color == Node::BLACK
850
+ delete_fixup(x)
851
+ end
852
+
853
+ if next_min_node
854
+ @min_node = next_min_node
855
+ end
856
+
857
+ value = z.value
858
+ release_node(z)
859
+ value
860
+ end
861
+
862
+ # Restores red-black tree properties after deletion.
863
+ #
864
+ # This method fixes any violations of red-black properties that may occur
865
+ # after removing a black node from the tree.
866
+ #
867
+ # @param x [Node] the node that needs rebalancing
868
+ # @return [void]
869
+ def delete_fixup(x)
870
+ while x != @root && x.color == Node::BLACK
871
+ if x == x.parent.left
872
+ w = x.parent.right
873
+ if w.color == Node::RED
874
+ w.color = Node::BLACK
875
+ x.parent.color = Node::RED
876
+ left_rotate(x.parent)
877
+ w = x.parent.right
878
+ end
879
+ if w.left.color == Node::BLACK && w.right.color == Node::BLACK
880
+ w.color = Node::RED
881
+ x = x.parent
882
+ else
883
+ if w.right.color == Node::BLACK
884
+ w.left.color = Node::BLACK
885
+ w.color = Node::RED
886
+ right_rotate(w)
887
+ w = x.parent.right
888
+ end
889
+ w.color = x.parent.color
890
+ x.parent.color = Node::BLACK
891
+ w.right.color = Node::BLACK
892
+ left_rotate(x.parent)
893
+ x = @root
894
+ end
895
+ else
896
+ w = x.parent.left
897
+ if w.color == Node::RED
898
+ w.color = Node::BLACK
899
+ x.parent.color = Node::RED
900
+ right_rotate(x.parent)
901
+ w = x.parent.left
902
+ end
903
+ if w.right.color == Node::BLACK && w.left.color == Node::BLACK
904
+ w.color = Node::RED
905
+ x = x.parent
906
+ else
907
+ if w.left.color == Node::BLACK
908
+ w.right.color = Node::BLACK
909
+ w.color = Node::RED
910
+ left_rotate(w)
911
+ w = x.parent.left
912
+ end
913
+ w.color = x.parent.color
914
+ x.parent.color = Node::BLACK
915
+ w.left.color = Node::BLACK
916
+ right_rotate(x.parent)
917
+ x = @root
918
+ end
919
+ end
920
+ end
921
+ x.color = Node::BLACK
922
+ end
923
+
924
+ # Replaces subtree rooted at node u with subtree rooted at node v.
925
+ #
926
+ # @param u [Node] the node to be replaced
927
+ # @param v [Node] the replacement node
928
+ # @return [void]
929
+ def transplant(u, v)
930
+ if u.parent == @nil_node
931
+ @root = v
932
+ elsif u == u.parent.left
933
+ u.parent.left = v
934
+ else
935
+ u.parent.right = v
936
+ end
937
+ v.parent = u.parent
938
+ end
939
+
940
+ # Searches for a node with the given key.
941
+ #
942
+ # @param key [Object] the key to search for
943
+ # @return [Node] the found node, or @nil_node if not found
944
+ def find_node(key)
945
+ current = @root
946
+ while current != @nil_node
947
+ cmp = key <=> current.key
948
+ if cmp == 0
949
+ return current
950
+ elsif cmp < 0
951
+ current = current.left
952
+ else
953
+ current = current.right
954
+ end
955
+ end
956
+ @nil_node
957
+ end
958
+
959
+ # Finds the node with the closest key to the given key.
960
+ #
961
+ # Uses numeric distance (absolute difference) to determine proximity.
962
+ # If multiple nodes have the same distance, returns the one with the smaller key.
963
+ #
964
+ # @param key [Numeric] the target key
965
+ # @return [Node] the nearest node, or @nil_node if tree is empty
966
+ def find_nearest_node(key)
967
+ current = @root
968
+ closest = @nil_node
969
+ min_dist = nil
970
+
971
+ while current != @nil_node
972
+ cmp = key <=> current.key
973
+ if cmp == 0
974
+ return current
975
+ end
976
+
977
+ # For nearest, we still typically rely on numeric distance.
978
+ # If keys are strings, this part will fail unless they support -.
979
+ dist = (current.key - key).abs
980
+
981
+ if closest == @nil_node || dist < min_dist
982
+ min_dist = dist
983
+ closest = current
984
+ elsif dist == min_dist
985
+ if (current.key <=> closest.key) < 0
986
+ closest = current
987
+ end
988
+ end
989
+
990
+ if cmp < 0
991
+ current = current.left
992
+ else
993
+ current = current.right
994
+ end
995
+ end
996
+ closest
997
+ end
998
+
999
+ # Finds the node with the largest key that is smaller than the given key.
1000
+ #
1001
+ # If the key exists in the tree, returns its predecessor node.
1002
+ # If the key does not exist, returns the largest node with key < given key.
1003
+ #
1004
+ # @param key [Object] the reference key
1005
+ # @return [Node] the predecessor node, or @nil_node if none exists
1006
+ def find_predecessor_node(key)
1007
+ # Check if key exists using O(1) hash lookup
1008
+ if (node = @hash_index[key])
1009
+ # Key exists: find predecessor in subtree or ancestors
1010
+ if node.left != @nil_node
1011
+ return rightmost(node.left)
1012
+ else
1013
+ # Walk up to find first ancestor where we came from the right
1014
+ current = node
1015
+ parent = current.parent
1016
+ while parent != @nil_node && current == parent.left
1017
+ current = parent
1018
+ parent = parent.parent
1019
+ end
1020
+ return parent
1021
+ end
1022
+ end
1023
+
1024
+ # Key doesn't exist: descend tree tracking the best candidate
1025
+ current = @root
1026
+ predecessor = @nil_node
1027
+ while current != @nil_node
1028
+ cmp = key <=> current.key
1029
+ if cmp > 0
1030
+ predecessor = current # This node's key < given key
1031
+ current = current.right
1032
+ else
1033
+ current = current.left
1034
+ end
1035
+ end
1036
+ predecessor
1037
+ end
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
+
1049
+ # Finds the node with the smallest key that is larger than the given key.
1050
+ #
1051
+ # If the key exists in the tree, returns its successor node.
1052
+ # If the key does not exist, returns the smallest node with key > given key.
1053
+ #
1054
+ # @param key [Object] the reference key
1055
+ # @return [Node] the successor node, or @nil_node if none exists
1056
+ def find_successor_node(key)
1057
+ # Check if key exists using O(1) hash lookup
1058
+ if (node = @hash_index[key])
1059
+ # Key exists: find successor in subtree or ancestors
1060
+ if node.right != @nil_node
1061
+ return leftmost(node.right)
1062
+ else
1063
+ # Walk up to find first ancestor where we came from the left
1064
+ current = node
1065
+ parent = current.parent
1066
+ while parent != @nil_node && current == parent.right
1067
+ current = parent
1068
+ parent = parent.parent
1069
+ end
1070
+ return parent
1071
+ end
1072
+ end
1073
+
1074
+ # Key doesn't exist: descend tree tracking the best candidate
1075
+ current = @root
1076
+ successor = @nil_node
1077
+ while current != @nil_node
1078
+ cmp = key <=> current.key
1079
+ if cmp < 0
1080
+ successor = current # This node's key > given key
1081
+ current = current.left
1082
+ else
1083
+ current = current.right
1084
+ end
1085
+ end
1086
+ successor
1087
+ end
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
+
1099
+ # Finds the leftmost (minimum) node in a subtree.
1100
+ #
1101
+ # @param node [Node] the root of the subtree
1102
+ # @return [Node] the leftmost node
1103
+ def leftmost(node)
1104
+ while node.left != @nil_node
1105
+ node = node.left
1106
+ end
1107
+ node
1108
+ end
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
+
1115
+ # Finds the rightmost (maximum) node in a subtree.
1116
+ #
1117
+ # @param node [Node] the root of the subtree
1118
+ # @return [Node] the rightmost node
1119
+ def rightmost(node)
1120
+ while node.right != @nil_node
1121
+ node = node.right
1122
+ end
1123
+ node
1124
+ end
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
+
1131
+ # Performs a left rotation on the given node.
1132
+ #
1133
+ # Transforms the tree structure:
1134
+ # x y
1135
+ # / \ / \
1136
+ # a y => x c
1137
+ # / \ / \
1138
+ # b c a b
1139
+ #
1140
+ # @param x [Node] the node to rotate
1141
+ # @return [void]
1142
+ def left_rotate(x)
1143
+ y = x.right
1144
+ x.right = y.left
1145
+ if y.left != @nil_node
1146
+ y.left.parent = x
1147
+ end
1148
+ y.parent = x.parent
1149
+ if x.parent == @nil_node
1150
+ @root = y
1151
+ elsif x == x.parent.left
1152
+ x.parent.left = y
1153
+ else
1154
+ x.parent.right = y
1155
+ end
1156
+ y.left = x
1157
+ x.parent = y
1158
+ end
1159
+
1160
+ # Performs a right rotation on the given node.
1161
+ #
1162
+ # Transforms the tree structure:
1163
+ # y x
1164
+ # / \ / \
1165
+ # x c => a y
1166
+ # / \ / \
1167
+ # a b b c
1168
+ #
1169
+ # @param y [Node] the node to rotate
1170
+ # @return [void]
1171
+ def right_rotate(y)
1172
+ x = y.left
1173
+ y.left = x.right
1174
+ if x.right != @nil_node
1175
+ x.right.parent = y
1176
+ end
1177
+ x.parent = y.parent
1178
+ if y.parent == @nil_node
1179
+ @root = x
1180
+ elsif y == y.parent.right
1181
+ y.parent.right = x
1182
+ else
1183
+ y.parent.left = x
1184
+ end
1185
+ x.right = y
1186
+ y.parent = x
1187
+ end
1188
+
1189
+ # Allocates a new node or recycles one from the pool.
1190
+ # @return [Node]
1191
+ def allocate_node(key, value, color, left, right, parent)
1192
+ if (node = @node_pool.pop)
1193
+ node.key = key
1194
+ node.value = value
1195
+ node.color = color
1196
+ node.left = left
1197
+ node.right = right
1198
+ node.parent = parent
1199
+ node
1200
+ else
1201
+ Node.new(key, value, color, left, right, parent)
1202
+ end
1203
+ end
1204
+
1205
+ # Releases a node back to the pool.
1206
+ # @param node [Node] the node to release
1207
+ def release_node(node)
1208
+ node.left = nil
1209
+ node.right = nil
1210
+ node.parent = nil
1211
+ node.value = nil # Help GC
1212
+ @node_pool << node
1213
+ end
1214
+
1215
+ # Recursively checks black height consistency.
1216
+ #
1217
+ # Verifies that:
1218
+ # - No red node has a red child
1219
+ # - All paths have the same black height
1220
+ #
1221
+ # @param node [Node] the current node
1222
+ # @return [Integer] the black height, or -1 if invalid
1223
+ def check_black_height(node)
1224
+ return 0 if node == @nil_node
1225
+
1226
+ if node.color == Node::RED
1227
+ return -1 if node.left.color == Node::RED || node.right.color == Node::RED
1228
+ end
1229
+
1230
+ left_h = check_black_height(node.left)
1231
+ right_h = check_black_height(node.right)
1232
+
1233
+ return -1 if left_h == -1 || right_h == -1 || left_h != right_h
1234
+
1235
+ left_h + (node.color == Node::BLACK ? 1 : 0)
1236
+ end
1237
+
1238
+ def check_order(node)
1239
+ return true if node == @nil_node
1240
+ if node.left != @nil_node && (node.left.key <=> node.key) >= 0
1241
+ return false
1242
+ end
1243
+ if node.right != @nil_node && (node.right.key <=> node.key) <= 0
1244
+ return false
1245
+ end
1246
+ check_order(node.left) && check_order(node.right)
1247
+ end
1248
+ end
1249
+
1250
+ # A Multi Red-Black Tree that allows duplicate keys.
1251
+ #
1252
+ # MultiRBTree extends RBTree to support multiple values per key. Each key maps to
1253
+ # an array of values rather than a single value. The size reflects the total
1254
+ # number of key-value pairs (not unique keys).
1255
+ #
1256
+ # == Features
1257
+ #
1258
+ # * Multiple values per key using arrays
1259
+ # * Separate methods for single deletion (`delete_one`) vs. all deletions (`delete`)
1260
+ # * Values for each key maintain insertion order
1261
+ # * Configurable access to first or last value via `:last` option
1262
+ #
1263
+ # == Value Array Access
1264
+ #
1265
+ # For each key, values are stored in insertion order. Methods that access
1266
+ # a single value support a `:last` option to choose which end of the array:
1267
+ #
1268
+ # * +get(key)+, +get_first(key)+ - returns first value (oldest)
1269
+ # * +get(key, last: true)+, +get_last(key)+ - returns last value (newest)
1270
+ # * +delete_one(key)+, +delete_first(key)+ - removes first value
1271
+ # * +delete_one(key, last: true)+, +delete_last(key)+ - removes last value
1272
+ # * +prev(key)+, +succ(key)+ - returns first value of adjacent key
1273
+ # * +prev(key, last: true)+, +succ(key, last: true)+ - returns last value
1274
+ #
1275
+ # == Boundary Operations
1276
+ #
1277
+ # * +min+, +max+ - return [key, first_value] by default
1278
+ # * +min(last: true)+, +max(last: true)+ - return [key, last_value]
1279
+ # * +shift+ - removes and returns [smallest_key, first_value]
1280
+ # * +pop+ - removes and returns [largest_key, last_value]
1281
+ #
1282
+ # == Iteration Order
1283
+ #
1284
+ # When iterating over values, the order depends on the direction:
1285
+ #
1286
+ # * Forward iteration (+each+, +lt+, +gt+, etc.): Each key's values are
1287
+ # yielded in insertion order (first to last).
1288
+ #
1289
+ # * Reverse iteration (+reverse_each+, +lt(key, reverse: true)+, etc.):
1290
+ # Each key's values are yielded in reverse insertion order (last to first).
1291
+ #
1292
+ # This ensures consistent behavior where reverse iteration is truly the
1293
+ # mirror image of forward iteration.
1294
+ #
1295
+ # == Usage
1296
+ #
1297
+ # tree = MultiRBTree.new
1298
+ # tree.insert(1, 'first one')
1299
+ # tree.insert(1, 'second one')
1300
+ # tree.insert(2, 'two')
1301
+ #
1302
+ # tree.size # => 3 (total key-value pairs)
1303
+ # tree.get(1) # => "first one" (first value)
1304
+ # tree.get(1, last: true) # => "second one" (last value)
1305
+ # tree.get_all(1) # => ["first one", "second one"] (all values)
1306
+ #
1307
+ # tree.delete_one(1) # removes only "first one"
1308
+ # tree.get(1) # => "second one"
1309
+ #
1310
+ # tree.delete(1) # removes all remaining values for key 1
1311
+ #
1312
+ # @author Masahito Suzuki
1313
+ # @since 0.1.2
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
+
1326
+ # Retrieves a value associated with the given key.
1327
+ #
1328
+ # @param key [Object] the key to look up
1329
+ # @param last [Boolean] if true, return the last value; otherwise return the first (default: false)
1330
+ # @return [Object, nil] the value for the key, or nil if not found
1331
+ # @example
1332
+ # tree = MultiRBTree.new
1333
+ # tree.insert(1, 'first')
1334
+ # tree.insert(1, 'second')
1335
+ # tree.get(1) # => "first"
1336
+ # tree.get(1, last: true) # => "second"
1337
+ def get(key, last: false)
1338
+ n = find_node(key)
1339
+ return nil if n == @nil_node || n.value.empty?
1340
+ last ? n.value.last : n.value.first
1341
+ end
1342
+
1343
+ # Retrieves the first value associated with the given key.
1344
+ #
1345
+ # @param key [Object] the key to look up
1346
+ # @return [Object, nil] the first value for the key, or nil if not found
1347
+ def get_first(key) = get(key, last: false)
1348
+
1349
+ # Retrieves the last value associated with the given key.
1350
+ #
1351
+ # @param key [Object] the key to look up
1352
+ # @return [Object, nil] the last value for the key, or nil if not found
1353
+ def get_last(key) = get(key, last: true)
1354
+
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
1360
+
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]
1371
+ end
1372
+
1373
+ # Inserts a value for the given key.
1374
+ #
1375
+ # If the key already exists, the value is appended to its list.
1376
+ # If the key doesn't exist, a new node is created.
1377
+ #
1378
+ # @param key [Object] the key (must implement <=>)
1379
+ # @param value [Object] the value to insert
1380
+ # @return [Boolean] always returns true
1381
+ # @example
1382
+ # tree = MultiRBTree.new
1383
+ # tree.insert(1, 'first')
1384
+ # tree.insert(1, 'second') # adds another value for key 1
1385
+ def insert(key, value)
1386
+ if (node = @hash_index[key])
1387
+ node.value << value
1388
+ @size += 1
1389
+ return true
1390
+ end
1391
+ y = @nil_node
1392
+ x = @root
1393
+ while x != @nil_node
1394
+ y = x
1395
+ cmp = key <=> x.key
1396
+ if cmp == 0
1397
+ x.value << value
1398
+ @size += 1
1399
+ return true
1400
+ elsif cmp < 0
1401
+ x = x.left
1402
+ else
1403
+ x = x.right
1404
+ end
1405
+ end
1406
+ z = allocate_node(key, [value], Node::RED, @nil_node, @nil_node, @nil_node)
1407
+ z.parent = y
1408
+ if y == @nil_node
1409
+ @root = z
1410
+ elsif (key <=> y.key) < 0
1411
+ y.left = z
1412
+ else
1413
+ y.right = z
1414
+ end
1415
+ z.left = @nil_node
1416
+ z.right = @nil_node
1417
+ z.color = Node::RED
1418
+ insert_fixup(z)
1419
+ @size += 1
1420
+
1421
+ if @min_node == @nil_node || (key <=> @min_node.key) < 0
1422
+ @min_node = z
1423
+ end
1424
+
1425
+ @hash_index[key] = z # Add to hash index
1426
+ true
1427
+ end
1428
+
1429
+ # Deletes a single value for the specified key.
1430
+ #
1431
+ # If the key has multiple values, removes only one value.
1432
+ # If this was the last value for the key, the node is removed from the tree.
1433
+ #
1434
+ # @param key [Object] the key to delete from
1435
+ # @param last [Boolean] if true, remove the last value; otherwise remove the first (default: false)
1436
+ # @return [Object, nil] the deleted value, or nil if key not found
1437
+ # @example
1438
+ # tree = MultiRBTree.new
1439
+ # tree.insert(1, 'first')
1440
+ # tree.insert(1, 'second')
1441
+ # tree.delete_one(1) # => "first"
1442
+ # tree.delete_one(1, last: true) # => "second" (if more values existed)
1443
+ def delete_one(key, last: false)
1444
+ z = @hash_index[key] # O(1) lookup
1445
+ return nil unless z
1446
+
1447
+ value = last ? z.value.pop : z.value.shift
1448
+ @size -= 1
1449
+ if z.value.empty?
1450
+ @hash_index.delete(key) # Remove from index when node removed
1451
+ remove_node(z)
1452
+ end
1453
+ value
1454
+ end
1455
+
1456
+ # Deletes the first value for the specified key.
1457
+ #
1458
+ # @param key [Object] the key to delete from
1459
+ # @return [Object, nil] the deleted value, or nil if key not found
1460
+ def delete_first(key) = delete_one(key, last: false)
1461
+
1462
+ # Deletes the last value for the specified key.
1463
+ #
1464
+ # @param key [Object] the key to delete from
1465
+ # @return [Object, nil] the deleted value, or nil if key not found
1466
+ def delete_last(key) = delete_one(key, last: true)
1467
+
1468
+ # Deletes all values for the specified key.
1469
+ #
1470
+ # Removes the node and all associated values.
1471
+ #
1472
+ # @param key [Object] the key to delete
1473
+ # @return [Array, nil] the array of all deleted values, or nil if not found
1474
+ # @example
1475
+ # tree = MultiRBTree.new
1476
+ # tree.insert(1, 'first')
1477
+ # tree.insert(1, 'second')
1478
+ # vals = tree.delete(1) # removes both values
1479
+ # vals.size # => 2
1480
+ def delete(key)
1481
+ z = @hash_index.delete(key) # O(1) lookup and remove from index
1482
+ return nil unless z
1483
+
1484
+ count = z.value.size
1485
+ remove_node(z)
1486
+ @size -= count
1487
+ z.value
1488
+ end
1489
+
1490
+ def shift
1491
+ return nil if @min_node == @nil_node
1492
+ node = @min_node
1493
+ key = node.key
1494
+ val = node.value.first
1495
+ node.value.shift
1496
+ @size -= 1
1497
+ if node.value.empty?
1498
+ delete_node(key)
1499
+ end
1500
+ [key, val]
1501
+ end
1502
+
1503
+ def pop
1504
+ n = rightmost(@root)
1505
+ return nil if n == @nil_node
1506
+ key = n.key
1507
+ val = n.value.last
1508
+ n.value.pop
1509
+ @size -= 1
1510
+ if n.value.empty?
1511
+ delete_node(key)
1512
+ end
1513
+ [key, val]
1514
+ end
1515
+
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 }
1528
+ end
1529
+
1530
+ private
1531
+
1532
+ def traverse_range_asc(...)
1533
+ super { |k, vals| vals.each { |v| yield k, v } }
1534
+ end
1535
+
1536
+ def traverse_range_desc(...)
1537
+ super { |k, vals| vals.reverse_each { |v| yield k, v } }
1538
+ end
1539
+ end
1540
+
1541
+ # Internal node structure for RBTree.
1542
+ #
1543
+ # Each node stores a key-value pair, color (red or black), and references
1544
+ # to parent, left child, and right child nodes.
1545
+ #
1546
+ # @!attribute [rw] key
1547
+ # @return [Object] the key stored in this node
1548
+ # @!attribute [rw] value
1549
+ # @return [Object] the value stored in this node
1550
+ # @!attribute [rw] color
1551
+ # @return [Symbol] the color of the node (:red or :black)
1552
+ # @!attribute [rw] left
1553
+ # @return [Node] the left child node
1554
+ # @!attribute [rw] right
1555
+ # @return [Node] the right child node
1556
+ # @!attribute [rw] parent
1557
+ # @return [Node] the parent node
1558
+ #
1559
+ # @api private
1560
+ class RBTree::Node
1561
+ attr_accessor :key, :value, :color, :left, :right, :parent
1562
+
1563
+ # Red color constant (true)
1564
+ RED = true
1565
+ # Black color constant (false)
1566
+ BLACK = false
1567
+
1568
+ # Creates a new Node.
1569
+ #
1570
+ # @param key [Object] the key
1571
+ # @param value [Object] the value
1572
+ # @param color [Boolean] the color (true=red, false=black)
1573
+ # @param left [Node] the left child
1574
+ # @param right [Node] the right child
1575
+ # @param parent [Node] the parent node
1576
+ def initialize(key = nil, value = nil, color = BLACK, left = nil, right = nil, parent = nil)
1577
+ @key = key
1578
+ @value = value
1579
+ @color = color
1580
+ @left = left
1581
+ @right = right
1582
+ @parent = parent
1583
+ end
1584
+
1585
+ # Returns the key-value pair.
1586
+ # @return [Array(Object, Object)] the key-value pair
1587
+ def pair = [key, value]
1588
+ end