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.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
|