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.rb CHANGED
@@ -56,7 +56,7 @@ class RBTree
56
56
 
57
57
  # Returns the number of key-value pairs stored in the tree.
58
58
  # @return [Integer] the number of entries in the tree
59
- attr_reader :size
59
+ attr_reader :key_count
60
60
 
61
61
  # Creates a new RBTree from the given arguments.
62
62
  #
@@ -100,7 +100,7 @@ class RBTree
100
100
  @min_node = @nil_node
101
101
  @hash_index = {} # Hash index for O(1) key lookup
102
102
  @node_pool = [] # Memory pool for recycling nodes
103
- @size = 0
103
+ @key_count = 0
104
104
 
105
105
  if args.size > 0 || block_given?
106
106
  insert(*args, overwrite: overwrite, &block)
@@ -110,7 +110,20 @@ class RBTree
110
110
  # Checks if the tree is empty.
111
111
  #
112
112
  # @return [Boolean] true if the tree contains no elements, false otherwise
113
- def empty? = @root == @nil_node
113
+ def empty? = @hash_index.empty?
114
+
115
+ # Returns the number of key-value pairs stored in the tree.
116
+ # @return [Integer] the number of entries in the tree
117
+ def size = @key_count
118
+ alias :value_count :size
119
+
120
+ # Returns the minimum key without removing it.
121
+ #
122
+ # @return [Object, nil] the minimum key, or nil if tree is empty
123
+ # @example
124
+ # tree = RBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
125
+ # tree.min_key # => 1
126
+ def min_key = min_node&.key
114
127
 
115
128
  # Returns the minimum key-value pair without removing it.
116
129
  #
@@ -118,7 +131,15 @@ class RBTree
118
131
  # @example
119
132
  # tree = RBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
120
133
  # tree.min # => [1, "one"]
121
- def min = find_min
134
+ def min = min_node&.pair
135
+
136
+ # Returns the maximum key without removing it.
137
+ #
138
+ # @return [Object, nil] the maximum key, or nil if tree is empty
139
+ # @example
140
+ # tree = RBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
141
+ # tree.max_key # => 3
142
+ def max_key = max_node&.key
122
143
 
123
144
  # Returns the maximum key-value pair without removing it.
124
145
  #
@@ -126,7 +147,23 @@ class RBTree
126
147
  # @example
127
148
  # tree = RBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
128
149
  # tree.max # => [3, "three"]
129
- def max = find_max
150
+ def max = max_node&.pair
151
+
152
+ # Returns the first key-value pair without removing it.
153
+ #
154
+ # @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
155
+ # @example
156
+ # tree = RBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
157
+ # tree.first # => [1, "one"]
158
+ def first = min
159
+
160
+ # Returns the last key-value pair without removing it.
161
+ #
162
+ # @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
163
+ # @example
164
+ # tree = RBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
165
+ # tree.last # => [3, "three"]
166
+ def last = max
130
167
 
131
168
  # Checks if the tree contains the given key.
132
169
  #
@@ -134,11 +171,10 @@ class RBTree
134
171
  # @return [Boolean] true if the key exists in the tree, false otherwise
135
172
  # @example
136
173
  # tree = RBTree.new({1 => 'one', 2 => 'two'})
137
- # tree.has_key?(1) # => true
138
- # tree.has_key?(3) # => false
139
- def has_key?(key)
140
- @hash_index.key?(key)
141
- end
174
+ # tree.key?(1) # => true
175
+ # tree.key?(3) # => false
176
+ def has_key?(key) = @hash_index.key?(key)
177
+ alias :key? :has_key?
142
178
 
143
179
  # Retrieves the value associated with the given key.
144
180
  #
@@ -149,10 +185,22 @@ class RBTree
149
185
  # tree.get(1) # => "one"
150
186
  # tree[2] # => "two"
151
187
  # tree[3] # => nil
152
- def get(key)
153
- @hash_index[key]&.value
154
- end
155
- alias_method :[], :get
188
+ def value(key) = @hash_index[key]&.value
189
+ alias :get :value
190
+ alias :[] :value
191
+
192
+ # Returns the key with the key closest to the given key.
193
+ #
194
+ # This method requires keys to be numeric or support subtraction and abs methods.
195
+ #
196
+ # @param key [Numeric] the target key
197
+ # @return [Object, nil] the key, or nil if tree is empty
198
+ # @example
199
+ # tree = RBTree.new({1 => 'one', 5 => 'five', 10 => 'ten'})
200
+ # tree.nearest_key(4) # => 5
201
+ # tree.nearest_key(7) # => 5
202
+ # tree.nearest_key(8) # => 10
203
+ def nearest_key(key) = ((n = find_nearest_node(key)) == @nil_node)? nil : n.key
156
204
 
157
205
  # Returns the key-value pair with the key closest to the given key.
158
206
  #
@@ -166,11 +214,21 @@ class RBTree
166
214
  # tree.nearest(4) # => [5, "five"]
167
215
  # tree.nearest(7) # => [5, "five"]
168
216
  # tree.nearest(8) # => [10, "ten"]
169
- def nearest(key)
170
- return nil unless key.respond_to?(:-)
171
- n = find_nearest_node(key)
172
- n == @nil_node ? nil : n.pair
173
- end
217
+ def nearest(key) = ((n = find_nearest_node(key)) == @nil_node)? nil : n.pair
218
+
219
+ # Returns the key with the largest key that is smaller than the given key.
220
+ #
221
+ # If the key exists in the tree, returns the predecessor (previous element).
222
+ # If the key does not exist, returns the largest key with key < given key.
223
+ #
224
+ # @param key [Object] the reference key
225
+ # @return [Object, nil] the key, or nil if no predecessor exists
226
+ # @example
227
+ # tree = RBTree.new({1 => 'one', 3 => 'three', 5 => 'five', 7 => 'seven'})
228
+ # tree.prev_key(5) # => 3
229
+ # tree.prev_key(4) # => 3 (4 does not exist)
230
+ # tree.prev_key(1) # => nil (no predecessor)
231
+ def prev_key(key) = ((n = find_predecessor_node(key)) == @nil_node)? nil : n.key
174
232
 
175
233
  # Returns the key-value pair with the largest key that is smaller than the given key.
176
234
  #
@@ -184,10 +242,21 @@ class RBTree
184
242
  # tree.prev(5) # => [3, "three"]
185
243
  # tree.prev(4) # => [3, "three"] (4 does not exist)
186
244
  # tree.prev(1) # => nil (no predecessor)
187
- def prev(key)
188
- n = find_predecessor_node(key)
189
- n == @nil_node ? nil : n.pair
190
- end
245
+ def prev(key) = ((n = find_predecessor_node(key)) == @nil_node)? nil : n.pair
246
+
247
+ # Returns the key with the smallest key that is larger than the given key.
248
+ #
249
+ # If the key exists in the tree, returns the successor (next element).
250
+ # If the key does not exist, returns the smallest key with key > given key.
251
+ #
252
+ # @param key [Object] the reference key
253
+ # @return [Object, nil] the key, or nil if no successor exists
254
+ # @example
255
+ # tree = RBTree.new({1 => 'one', 3 => 'three', 5 => 'five', 7 => 'seven'})
256
+ # tree.succ_key(5) # => 7
257
+ # tree.succ_key(4) # => 5 (4 does not exist)
258
+ # tree.succ_key(1) # => 3 (1 does not exist)
259
+ def succ_key(key) = ((n = find_successor_node(key)) == @nil_node)? nil : n.key
191
260
 
192
261
  # Returns the key-value pair with the smallest key that is larger than the given key.
193
262
  #
@@ -201,10 +270,7 @@ class RBTree
201
270
  # tree.succ(5) # => [7, "seven"]
202
271
  # tree.succ(4) # => [5, "five"] (4 does not exist)
203
272
  # tree.succ(7) # => nil (no successor)
204
- def succ(key)
205
- n = find_successor_node(key)
206
- n == @nil_node ? nil : n.pair
207
- end
273
+ def succ(key) = ((n = find_successor_node(key)) == @nil_node)? nil : n.pair
208
274
 
209
275
  # Inserts one or more key-value pairs into the tree.
210
276
  #
@@ -268,7 +334,7 @@ class RBTree
268
334
  end
269
335
  end
270
336
  end
271
- alias_method :[]=, :insert
337
+ alias :[]= :insert
272
338
 
273
339
  # Deletes the key-value pair with the specified key.
274
340
  #
@@ -278,12 +344,12 @@ class RBTree
278
344
  # tree = RBTree.new({1 => 'one', 2 => 'two'})
279
345
  # tree.delete(1) # => "one"
280
346
  # tree.delete(3) # => nil
281
- def delete(key)
282
- value = delete_node(key)
283
- return nil unless value
284
- @size -= 1
347
+ def delete_key(key)
348
+ return nil unless (value = (z = @hash_index[key])&.value)
349
+ delete_indexed_node(key)
285
350
  value
286
351
  end
352
+ alias :delete :delete_key
287
353
 
288
354
  # Removes and returns the minimum key-value pair.
289
355
  #
@@ -293,10 +359,10 @@ class RBTree
293
359
  # tree.shift # => [1, "one"]
294
360
  # tree.shift # => [2, "two"]
295
361
  def shift
296
- return nil if @min_node == @nil_node
297
- result = [@min_node.key, @min_node.value]
298
- delete(@min_node.key)
299
- result
362
+ return nil unless (n = @min_node) != @nil_node
363
+ pair = n.pair
364
+ delete(n.key)
365
+ pair
300
366
  end
301
367
 
302
368
  # Removes and returns the maximum key-value pair.
@@ -307,21 +373,46 @@ class RBTree
307
373
  # tree.pop # => [3, "three"]
308
374
  # tree.pop # => [2, "two"]
309
375
  def pop
310
- n = rightmost(@root)
311
- return nil if n == @nil_node
312
- result = n.pair
376
+ return nil unless (n = rightmost(@root)) != @nil_node
377
+ pair = n.pair
313
378
  delete(n.key)
314
- result
379
+ pair
315
380
  end
316
381
 
317
382
  # Removes all key-value pairs from the tree.
318
383
  #
319
384
  # @return [RBTree] self
320
385
  def clear
321
- @root = @nil_node
322
- @min_node = @nil_node
386
+ @root = @min_node = @nil_node
323
387
  @hash_index.clear
324
- @size = 0
388
+ @key_count = 0
389
+ self
390
+ end
391
+
392
+ # Iterates over all keys in ascending (or descending) order.
393
+ #
394
+ # @param reverse [Boolean] if true, iterate in descending order (default: false)
395
+ # @param safe [Boolean] if true, safe for modifications during iteration (default: false)
396
+ # @yield [key] each key in the tree
397
+ # @return [Enumerator, RBTree] an Enumerator if no block is given, self otherwise
398
+ # @example
399
+ # tree = RBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
400
+ # tree.keys { |k| puts k }
401
+ # # Output:
402
+ # # 1
403
+ # # 2
404
+ # # 3
405
+ #
406
+ # # Reverse iteration
407
+ # tree.keys(reverse: true) { |k| ... }
408
+ #
409
+ # # Safe iteration for modifications
410
+ # tree.keys(safe: true) do |k|
411
+ # tree.delete(k) if k.even?
412
+ # end
413
+ def keys(reverse: false, safe: false, &block)
414
+ return enum_for(:keys, reverse: reverse, safe: safe) { @key_count } unless block_given?
415
+ each(reverse: reverse, safe: safe) { |key, _| yield key }
325
416
  self
326
417
  end
327
418
 
@@ -347,7 +438,7 @@ class RBTree
347
438
  # tree.delete(k) if k.even?
348
439
  # end
349
440
  def each(reverse: false, safe: false, &block)
350
- return enum_for(:each, reverse: reverse, safe: safe) unless block_given?
441
+ return enum_for(:each, reverse: reverse, safe: safe) { size } unless block_given?
351
442
  if reverse
352
443
  traverse_all_desc(@root, safe: safe, &block)
353
444
  else
@@ -375,7 +466,10 @@ class RBTree
375
466
  # @yield [key, value] each key-value pair in the tree
376
467
  # @return [Enumerator, RBTree] an Enumerator if no block is given, self otherwise
377
468
  # @see #each
378
- def reverse_each(safe: false, &block) = each(reverse: true, safe: safe, &block)
469
+ def reverse_each(safe: false, &block)
470
+ return enum_for(:reverse_each, safe: safe) { size } unless block_given?
471
+ each(reverse: true, safe: safe, &block)
472
+ end
379
473
 
380
474
  # Retrieves all key-value pairs with keys less than the specified key.
381
475
  #
@@ -492,13 +586,9 @@ class RBTree
492
586
  #
493
587
  # @return [String] a human-readable representation of the tree
494
588
  def inspect
495
- if @size > 0
496
- content = first(5).map { |k, v| "#{k.inspect}=>#{v.inspect}" }.join(", ")
497
- suffix = @size > 5 ? ", ..." : ""
498
- "#<#{self.class}:0x#{object_id.to_s(16)} size=#{@size} {#{content}#{suffix}}>"
499
- else
500
- super
501
- end
589
+ content = take(5).map { |k, v| "#{k.inspect}=>#{v.inspect}" }.join(", ")
590
+ suffix = size > 5 ? ", ..." : ""
591
+ "#<#{self.class}:0x#{object_id.to_s(16)} size=#{size} {#{content}#{suffix}}>"
502
592
  end
503
593
 
504
594
  # Validates the red-black tree properties.
@@ -517,8 +607,12 @@ class RBTree
517
607
  true
518
608
  end
519
609
 
520
- # @!visibility protected
521
- protected
610
+ # @!visibility private
611
+ private
612
+
613
+ def min_node = ((n = @min_node) == @nil_node) ? nil : n
614
+
615
+ def max_node = ((n = rightmost(@root)) == @nil_node) ? nil : n
522
616
 
523
617
  # Inserts a single key-value pair.
524
618
  #
@@ -560,7 +654,6 @@ class RBTree
560
654
  z.right = @nil_node
561
655
  z.color = Node::RED
562
656
  insert_fixup(z)
563
- @size += 1
564
657
 
565
658
  if @min_node == @nil_node || (key <=> @min_node.key) < 0
566
659
  @min_node = z
@@ -846,11 +939,7 @@ class RBTree
846
939
  #
847
940
  # @param key [Object] the key to delete
848
941
  # @return [Object, nil] the value of the deleted node, or nil if not found
849
- def delete_node(key)
850
- z = @hash_index.delete(key) # O(1) lookup and remove from index
851
- return nil unless z
852
- remove_node(z)
853
- end
942
+ def delete_indexed_node(key) = (z = @hash_index.delete(key)) && delete_node(z)
854
943
 
855
944
  # Removes a node from the tree and restores red-black properties.
856
945
  #
@@ -861,7 +950,7 @@ class RBTree
861
950
  #
862
951
  # @param z [Node] the node to remove
863
952
  # @return [Object] the value of the removed node
864
- def remove_node(z)
953
+ def delete_node(z)
865
954
  next_min_node = nil
866
955
  if z == @min_node
867
956
  if z.right != @nil_node
@@ -986,25 +1075,6 @@ class RBTree
986
1075
  v.parent = u.parent
987
1076
  end
988
1077
 
989
- # Searches for a node with the given key.
990
- #
991
- # @param key [Object] the key to search for
992
- # @return [Node] the found node, or @nil_node if not found
993
- def find_node(key)
994
- current = @root
995
- while current != @nil_node
996
- cmp = key <=> current.key
997
- if cmp == 0
998
- return current
999
- elsif cmp < 0
1000
- current = current.left
1001
- else
1002
- current = current.right
1003
- end
1004
- end
1005
- @nil_node
1006
- end
1007
-
1008
1078
  # Finds the node with the closest key to the given key.
1009
1079
  #
1010
1080
  # Uses numeric distance (absolute difference) to determine proximity.
@@ -1159,7 +1229,7 @@ class RBTree
1159
1229
  # Returns the minimum key-value pair.
1160
1230
  #
1161
1231
  # @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
1162
- def find_min = @min_node == @nil_node ? nil : @min_node.pair
1232
+ def find_min = ((n = @min_node) != @nil_node) && n.pair
1163
1233
 
1164
1234
  # Finds the rightmost (maximum) node in a subtree.
1165
1235
  #
@@ -1175,7 +1245,7 @@ class RBTree
1175
1245
  # Returns the maximum key-value pair.
1176
1246
  #
1177
1247
  # @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
1178
- def find_max = (n = rightmost(@root)) == @nil_node ? nil : n.pair
1248
+ def find_max = ((n = rightmost(@root)) != @nil_node) && n.pair
1179
1249
 
1180
1250
  # Performs a left rotation on the given node.
1181
1251
  #
@@ -1238,7 +1308,8 @@ class RBTree
1238
1308
  # Allocates a new node or recycles one from the pool.
1239
1309
  # @return [Node]
1240
1310
  def allocate_node(key, value, color, left, right, parent)
1241
- if (node = @node_pool.pop)
1311
+ node = @node_pool.pop
1312
+ if node
1242
1313
  node.key = key
1243
1314
  node.value = value
1244
1315
  node.color = color
@@ -1247,8 +1318,10 @@ class RBTree
1247
1318
  node.parent = parent
1248
1319
  node
1249
1320
  else
1250
- Node.new(key, value, color, left, right, parent)
1321
+ node = Node.new(key, value, color, left, right, parent)
1251
1322
  end
1323
+ @key_count += 1
1324
+ node
1252
1325
  end
1253
1326
 
1254
1327
  # Releases a node back to the pool.
@@ -1259,6 +1332,7 @@ class RBTree
1259
1332
  node.parent = nil
1260
1333
  node.value = nil # Help GC
1261
1334
  @node_pool << node
1335
+ @key_count -= 1
1262
1336
  end
1263
1337
 
1264
1338
  # Recursively checks black height consistency.
@@ -1305,7 +1379,7 @@ end
1305
1379
  # == Features
1306
1380
  #
1307
1381
  # * Multiple values per key using arrays
1308
- # * Separate methods for single deletion (`delete_one`) vs. all deletions (`delete`)
1382
+ # * Separate methods for single deletion (`delete_value`) vs. all deletions (`delete_key`)
1309
1383
  # * Values for each key maintain insertion order
1310
1384
  # * Configurable access to first or last value via `:last` option
1311
1385
  #
@@ -1314,10 +1388,10 @@ end
1314
1388
  # For each key, values are stored in insertion order. Methods that access
1315
1389
  # a single value support a `:last` option to choose which end of the array:
1316
1390
  #
1317
- # * +get(key)+, +get_first(key)+ - returns first value (oldest)
1318
- # * +get(key, last: true)+, +get_last(key)+ - returns last value (newest)
1319
- # * +delete_one(key)+, +delete_first(key)+ - removes first value
1320
- # * +delete_one(key, last: true)+, +delete_last(key)+ - removes last value
1391
+ # * +get(key)+, +first_value(key)+ - returns first value (oldest)
1392
+ # * +get(key, last: true)+, +last_value(key)+ - returns last value (newest)
1393
+ # * +delete_value(key)+, +delete_first_value(key)+ - removes first value
1394
+ # * +delete_value(key, last: true)+, +delete_last_value(key)+ - removes last value
1321
1395
  # * +prev(key)+, +succ(key)+ - returns first value of adjacent key
1322
1396
  # * +prev(key, last: true)+, +succ(key, last: true)+ - returns last value
1323
1397
  #
@@ -1351,9 +1425,9 @@ end
1351
1425
  # tree.size # => 3 (total key-value pairs)
1352
1426
  # tree.get(1) # => "first one" (first value)
1353
1427
  # tree.get(1, last: true) # => "second one" (last value)
1354
- # tree.get_all(1) # => ["first one", "second one"] (all values)
1428
+ # tree.values(1) # => ["first one", "second one"] (all values)
1355
1429
  #
1356
- # tree.delete_one(1) # removes only "first one"
1430
+ # tree.delete_value(1) # removes only "first one"
1357
1431
  # tree.get(1) # => "second one"
1358
1432
  #
1359
1433
  # tree.delete(1) # removes all remaining values for key 1
@@ -1361,16 +1435,46 @@ end
1361
1435
  # @author Masahito Suzuki
1362
1436
  # @since 0.1.2
1363
1437
  class MultiRBTree < RBTree
1364
- def min(last: false)
1365
- return nil if @min_node == @nil_node || @min_node.value.empty?
1366
- [@min_node.key, last ? @min_node.value.last : @min_node.value.first]
1438
+ def initialize(*args, **kwargs)
1439
+ @value_count = 0
1440
+ super
1367
1441
  end
1368
1442
 
1369
- def max(last: false)
1370
- n = rightmost(@root)
1371
- return nil if n == @nil_node || n.value.empty?
1372
- [n.key, last ? n.value.last : n.value.first]
1373
- end
1443
+ # Returns the number of values stored in the tree.
1444
+ # @return [Integer] the number of values in the tree
1445
+ def size = @value_count
1446
+
1447
+ # Returns the minimum key-value pair without removing it.
1448
+ #
1449
+ # @param last [Boolean] whether to return the last value (default: false)
1450
+ # @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
1451
+ # @example
1452
+ # tree = MultiRBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
1453
+ # tree.min # => [1, "one"]
1454
+ def min(last: false) = (n = min_node) && [n.key, n.value.send(last ? :last : :first)]
1455
+
1456
+ # Returns the maximum key-value pair without removing it.
1457
+ #
1458
+ # @param last [Boolean] whether to return the last value (default: false)
1459
+ # @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
1460
+ # @example
1461
+ # tree = MultiRBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
1462
+ # tree.max # => [3, "three"]
1463
+ def max(last: false) = (n = max_node) && [n.key, n.value.send(last ? :last : :first)]
1464
+
1465
+ # Returns the last key-value pair without removing it.
1466
+ #
1467
+ # @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
1468
+ # @example
1469
+ # tree = MultiRBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
1470
+ # tree.last # => [3, "three"]
1471
+ def last = max(last: true)
1472
+
1473
+ # Returns the number of values for a given key or the total number of key-value pairs if no key is given.
1474
+ #
1475
+ # @param key [Object, nil] the key to look up, or nil for total count
1476
+ # @return [Integer] the number of values for the key, or total count if no key is given
1477
+ def value_count(key = nil) = !key ? size : (@hash_index[key]&.value&.size || 0)
1374
1478
 
1375
1479
  # Retrieves a value associated with the given key.
1376
1480
  #
@@ -1383,41 +1487,66 @@ class MultiRBTree < RBTree
1383
1487
  # tree.insert(1, 'second')
1384
1488
  # tree.get(1) # => "first"
1385
1489
  # tree.get(1, last: true) # => "second"
1386
- def get(key, last: false)
1387
- n = find_node(key)
1388
- return nil if n == @nil_node || n.value.empty?
1389
- last ? n.value.last : n.value.first
1390
- end
1490
+ def value(key, last: false) = @hash_index[key]&.value&.send(last ? :last : :first)
1391
1491
 
1392
1492
  # Retrieves the first value associated with the given key.
1393
1493
  #
1394
1494
  # @param key [Object] the key to look up
1395
1495
  # @return [Object, nil] the first value for the key, or nil if not found
1396
- def get_first(key) = get(key, last: false)
1496
+ def first_value(key) = value(key)
1497
+ alias :get_first :first_value
1397
1498
 
1398
1499
  # Retrieves the last value associated with the given key.
1399
1500
  #
1400
1501
  # @param key [Object] the key to look up
1401
1502
  # @return [Object, nil] the last value for the key, or nil if not found
1402
- def get_last(key) = get(key, last: true)
1503
+ def last_value(key) = value(key, last: true)
1504
+ alias :get_last :last_value
1403
1505
 
1404
- def nearest(key, last: false)
1405
- n = find_nearest_node(key)
1406
- return nil if n == @nil_node || n.value.empty?
1407
- [n.key, last ? n.value.last : n.value.first]
1506
+ # Retrieves all values associated with the given key.
1507
+ #
1508
+ # @param key [Object] the key to look up
1509
+ # @return [Array, nil] an Array containing all values, or nil if not found
1510
+ # @example
1511
+ # tree = MultiRBTree.new
1512
+ # tree.insert(1, 'first')
1513
+ # tree.insert(1, 'second')
1514
+ # tree.values(1).to_a # => ["first", "second"]
1515
+ def values(key, reverse: false)
1516
+ return enum_for(:values, key) { value_count(key) } unless block_given?
1517
+ @hash_index[key]&.value&.send(reverse ? :reverse_each : :each) { |v| yield v }
1408
1518
  end
1519
+ alias :get_all :values
1409
1520
 
1410
- def prev(key, last: false)
1411
- pair = super(key)
1412
- return nil unless pair
1413
- [pair[0], last ? pair[1].last : pair[1].first]
1414
- end
1415
-
1416
- def succ(key, last: false)
1417
- pair = super(key)
1418
- return nil unless pair
1419
- [pair[0], last ? pair[1].last : pair[1].first]
1420
- end
1521
+ # Returns the nearest key-value pair without removing it.
1522
+ #
1523
+ # @param key [Object] the target key
1524
+ # @param last [Boolean] whether to return the last value (default: false)
1525
+ # @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
1526
+ # @example
1527
+ # tree = MultiRBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
1528
+ # tree.nearest(4) # => [5, "five"]
1529
+ def nearest(key, last: false) = (pair = super(key)) && [pair[0], pair[1].send(last ? :last : :first)]
1530
+
1531
+ # Returns the previous key-value pair without removing it.
1532
+ #
1533
+ # @param key [Object] the target key
1534
+ # @param last [Boolean] whether to return the last value (default: false)
1535
+ # @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
1536
+ # @example
1537
+ # tree = MultiRBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
1538
+ # tree.prev(4) # => [5, "five"]
1539
+ def prev(key, last: false) = (pair = super(key)) && [pair[0], pair[1].send(last ? :last : :first)]
1540
+
1541
+ # Returns the next key-value pair without removing it.
1542
+ #
1543
+ # @param key [Object] the target key
1544
+ # @param last [Boolean] whether to return the last value (default: false)
1545
+ # @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
1546
+ # @example
1547
+ # tree = MultiRBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
1548
+ # tree.succ(4) # => [5, "five"]
1549
+ def succ(key, last: false) = (pair = super(key)) && [pair[0], pair[1].send(last ? :last : :first)]
1421
1550
 
1422
1551
  # Inserts a value for the given key.
1423
1552
  #
@@ -1435,7 +1564,7 @@ class MultiRBTree < RBTree
1435
1564
  def insert_entry(key, value, **)
1436
1565
  if (node = @hash_index[key])
1437
1566
  node.value << value
1438
- @size += 1
1567
+ @value_count += 1
1439
1568
  return true
1440
1569
  end
1441
1570
  y = @nil_node
@@ -1445,7 +1574,7 @@ class MultiRBTree < RBTree
1445
1574
  cmp = key <=> x.key
1446
1575
  if cmp == 0
1447
1576
  x.value << value
1448
- @size += 1
1577
+ @value_count += 1
1449
1578
  return true
1450
1579
  elsif cmp < 0
1451
1580
  x = x.left
@@ -1466,7 +1595,7 @@ class MultiRBTree < RBTree
1466
1595
  z.right = @nil_node
1467
1596
  z.color = Node::RED
1468
1597
  insert_fixup(z)
1469
- @size += 1
1598
+ @value_count += 1
1470
1599
 
1471
1600
  if @min_node == @nil_node || (key <=> @min_node.key) < 0
1472
1601
  @min_node = z
@@ -1488,32 +1617,30 @@ class MultiRBTree < RBTree
1488
1617
  # tree = MultiRBTree.new
1489
1618
  # tree.insert(1, 'first')
1490
1619
  # tree.insert(1, 'second')
1491
- # tree.delete_one(1) # => "first"
1492
- # tree.delete_one(1, last: true) # => "second" (if more values existed)
1493
- def delete_one(key, last: false)
1494
- z = @hash_index[key] # O(1) lookup
1495
- return nil unless z
1496
-
1497
- value = last ? z.value.pop : z.value.shift
1498
- @size -= 1
1499
- if z.value.empty?
1500
- @hash_index.delete(key) # Remove from index when node removed
1501
- remove_node(z)
1502
- end
1620
+ # tree.delete_value(1) # => "first"
1621
+ # tree.delete_value(1, last: true) # => "second" (if more values existed)
1622
+ def delete_value(key, last: false)
1623
+ (z = @hash_index[key]) or return nil
1624
+ value = z.value.send(last ? :pop : :shift)
1625
+ z.value.empty? && delete_indexed_node(key)
1626
+ @value_count -= 1
1503
1627
  value
1504
1628
  end
1629
+ alias :delete_one :delete_value
1505
1630
 
1506
1631
  # Deletes the first value for the specified key.
1507
1632
  #
1508
1633
  # @param key [Object] the key to delete from
1509
1634
  # @return [Object, nil] the deleted value, or nil if key not found
1510
- def delete_first(key) = delete_one(key, last: false)
1635
+ def delete_first_value(key) = delete_value(key)
1636
+ alias :delete_first :delete_first_value
1511
1637
 
1512
1638
  # Deletes the last value for the specified key.
1513
1639
  #
1514
1640
  # @param key [Object] the key to delete from
1515
1641
  # @return [Object, nil] the deleted value, or nil if key not found
1516
- def delete_last(key) = delete_one(key, last: true)
1642
+ def delete_last_value(key) = delete_value(key, last: true)
1643
+ alias :delete_last :delete_last_value
1517
1644
 
1518
1645
  # Deletes all values for the specified key.
1519
1646
  #
@@ -1527,65 +1654,62 @@ class MultiRBTree < RBTree
1527
1654
  # tree.insert(1, 'second')
1528
1655
  # vals = tree.delete(1) # removes both values
1529
1656
  # vals.size # => 2
1530
- def delete(key)
1531
- z = @hash_index.delete(key) # O(1) lookup and remove from index
1532
- return nil unless z
1533
-
1534
- count = z.value.size
1535
- remove_node(z)
1536
- @size -= count
1537
- z.value
1657
+ def delete_key(key)
1658
+ return nil unless (z = @hash_index[key])
1659
+ @value_count -= (value = z.value).size
1660
+ delete_indexed_node(z.key)
1661
+ value
1538
1662
  end
1539
1663
 
1664
+ # Removes and returns the first key-value pair.
1665
+ #
1666
+ # @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
1667
+ # @example
1668
+ # tree = MultiRBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
1669
+ # tree.shift # => [1, "one"]
1540
1670
  def shift
1541
- return nil if @min_node == @nil_node
1542
- node = @min_node
1543
- key = node.key
1544
- val = node.value.first
1545
- node.value.shift
1546
- @size -= 1
1547
- if node.value.empty?
1548
- delete_node(key)
1549
- end
1550
- [key, val]
1551
- end
1552
-
1553
- def pop
1554
- n = rightmost(@root)
1555
- return nil if n == @nil_node
1556
- key = n.key
1557
- val = n.value.last
1558
- n.value.pop
1559
- @size -= 1
1560
- if n.value.empty?
1561
- delete_node(key)
1562
- end
1671
+ (key, vals = min_node&.pair) or return nil
1672
+ val = vals.shift
1673
+ vals.empty? && delete_indexed_node(key)
1674
+ @value_count -= 1
1563
1675
  [key, val]
1564
1676
  end
1565
1677
 
1566
- # Retrieves all values associated with the given key.
1678
+ # Removes and returns the last key-value pair.
1567
1679
  #
1568
- # @param key [Object] the key to look up
1569
- # @return [Array, nil] an Array containing all values, or nil if not found
1680
+ # @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
1570
1681
  # @example
1571
- # tree = MultiRBTree.new
1572
- # tree.insert(1, 'first')
1573
- # tree.insert(1, 'second')
1574
- # tree.get_all(1).to_a # => ["first", "second"]
1575
- def get_all(key)
1576
- return enum_for(:get_all, key) unless block_given?
1577
- @hash_index[key]&.value&.each { |v| yield v }
1682
+ # tree = MultiRBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
1683
+ # tree.pop # => [3, "three"]
1684
+ def pop
1685
+ (key, vals = max_node&.pair) or return nil
1686
+ val = vals.pop
1687
+ vals.empty? && delete_indexed_node(key)
1688
+ @value_count -= 1
1689
+ [key, val]
1578
1690
  end
1579
1691
 
1580
- # @!visibility protected
1581
- protected
1692
+ # @!visibility private
1693
+ private
1582
1694
 
1695
+ # Traverses the tree in ascending order, yielding each key-value pair.
1696
+ #
1697
+ # @param range [Range] the range of keys to traverse
1698
+ # @yield [Array(Object, Object)] each key-value pair
1699
+ # @yieldparam key [Object] the key
1700
+ # @yieldparam val [Object] the value
1583
1701
  def traverse_range_asc(...)
1584
- super { |k, vals| vals.each { |v| yield k, v } }
1702
+ super { |k, vals| vals.each { |v| yield [k, v] } }
1585
1703
  end
1586
1704
 
1705
+ # Traverses the tree in descending order, yielding each key-value pair.
1706
+ #
1707
+ # @param range [Range] the range of keys to traverse
1708
+ # @yield [Array(Object, Object)] each key-value pair
1709
+ # @yieldparam key [Object] the key
1710
+ # @yieldparam val [Object] the value
1587
1711
  def traverse_range_desc(...)
1588
- super { |k, vals| vals.reverse_each { |v| yield k, v } }
1712
+ super { |k, vals| vals.reverse_each { |v| yield [k, v] } }
1589
1713
  end
1590
1714
  end
1591
1715