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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +25 -0
- data/README.ja.md +13 -13
- data/README.md +13 -13
- data/lib/rbtree/version.rb +1 -1
- data/lib/rbtree.old.rb +1588 -0
- data/lib/rbtree.rb +306 -182
- metadata +2 -1
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 :
|
|
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
|
-
@
|
|
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? = @
|
|
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 =
|
|
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 =
|
|
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.
|
|
138
|
-
# tree.
|
|
139
|
-
def has_key?(key)
|
|
140
|
-
|
|
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
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
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
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
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
|
-
|
|
189
|
-
|
|
190
|
-
|
|
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
|
-
|
|
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
|
|
282
|
-
value =
|
|
283
|
-
|
|
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
|
|
297
|
-
|
|
298
|
-
delete(
|
|
299
|
-
|
|
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
|
-
|
|
312
|
-
result = n.pair
|
|
376
|
+
return nil unless (n = rightmost(@root)) != @nil_node
|
|
377
|
+
pair = n.pair
|
|
313
378
|
delete(n.key)
|
|
314
|
-
|
|
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
|
-
@
|
|
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)
|
|
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
|
-
|
|
496
|
-
|
|
497
|
-
|
|
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
|
|
521
|
-
|
|
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
|
|
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
|
|
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
|
|
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))
|
|
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
|
-
|
|
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 (`
|
|
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)+, +
|
|
1318
|
-
# * +get(key, last: true)+, +
|
|
1319
|
-
# * +
|
|
1320
|
-
# * +
|
|
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.
|
|
1428
|
+
# tree.values(1) # => ["first one", "second one"] (all values)
|
|
1355
1429
|
#
|
|
1356
|
-
# tree.
|
|
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
|
|
1365
|
-
|
|
1366
|
-
|
|
1438
|
+
def initialize(*args, **kwargs)
|
|
1439
|
+
@value_count = 0
|
|
1440
|
+
super
|
|
1367
1441
|
end
|
|
1368
1442
|
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
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
|
|
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
|
|
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
|
|
1503
|
+
def last_value(key) = value(key, last: true)
|
|
1504
|
+
alias :get_last :last_value
|
|
1403
1505
|
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
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
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
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
|
-
@
|
|
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
|
-
@
|
|
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
|
-
@
|
|
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.
|
|
1492
|
-
# tree.
|
|
1493
|
-
def
|
|
1494
|
-
z = @hash_index[key]
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
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
|
|
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
|
|
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
|
|
1531
|
-
z = @hash_index
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
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
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
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
|
-
#
|
|
1678
|
+
# Removes and returns the last key-value pair.
|
|
1567
1679
|
#
|
|
1568
|
-
# @
|
|
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.
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
@
|
|
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
|
|
1581
|
-
|
|
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
|
|