rbtree-ruby 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +52 -0
- data/LICENSE +21 -0
- data/README.md +179 -0
- data/Rakefile +31 -0
- data/lib/rbtree/version.rb +6 -0
- data/lib/rbtree.rb +1260 -0
- data/rbtree-ruby.gemspec +43 -0
- metadata +9 -2
data/lib/rbtree.rb
ADDED
|
@@ -0,0 +1,1260 @@
|
|
|
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
|
+
@size = 0
|
|
96
|
+
|
|
97
|
+
if args.any?
|
|
98
|
+
source = args.size == 1 ? args.first : args
|
|
99
|
+
case source
|
|
100
|
+
when Hash
|
|
101
|
+
source.each { |k, v| insert(k, v) }
|
|
102
|
+
when Array
|
|
103
|
+
source.each do |arg|
|
|
104
|
+
key, value = arg
|
|
105
|
+
insert(key, value)
|
|
106
|
+
end
|
|
107
|
+
else
|
|
108
|
+
raise ArgumentError, "Invalid arguments"
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Returns a string representation of the tree.
|
|
114
|
+
#
|
|
115
|
+
# Shows the first 5 entries and total size. Useful for debugging.
|
|
116
|
+
#
|
|
117
|
+
# @return [String] a human-readable representation of the tree
|
|
118
|
+
def inspect
|
|
119
|
+
if @size > 0
|
|
120
|
+
content = first(5).map { |k, v| "#{k.inspect}=>#{v.inspect}" }.join(", ")
|
|
121
|
+
suffix = @size > 5 ? ", ..." : ""
|
|
122
|
+
"#<#{self.class}:0x#{object_id.to_s(16)} size=#{@size} {#{content}#{suffix}}>"
|
|
123
|
+
else
|
|
124
|
+
super
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Checks if the tree is empty.
|
|
129
|
+
#
|
|
130
|
+
# @return [Boolean] true if the tree contains no elements, false otherwise
|
|
131
|
+
def empty? = @root == @nil_node
|
|
132
|
+
|
|
133
|
+
# Checks if the tree contains the given key.
|
|
134
|
+
#
|
|
135
|
+
# @param key [Object] the key to search for
|
|
136
|
+
# @return [Boolean] true if the key exists in the tree, false otherwise
|
|
137
|
+
# @example
|
|
138
|
+
# tree = RBTree.new({1 => 'one', 2 => 'two'})
|
|
139
|
+
# tree.has_key?(1) # => true
|
|
140
|
+
# tree.has_key?(3) # => false
|
|
141
|
+
def has_key?(key)
|
|
142
|
+
find_node(key) != @nil_node
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Retrieves the value associated with the given key.
|
|
146
|
+
#
|
|
147
|
+
# @param key [Object] the key to look up
|
|
148
|
+
# @return [Object, nil] the associated value, or nil if the key is not found
|
|
149
|
+
# @example
|
|
150
|
+
# tree = RBTree.new({1 => 'one', 2 => 'two'})
|
|
151
|
+
# tree.get(1) # => "one"
|
|
152
|
+
# tree[2] # => "two"
|
|
153
|
+
# tree[3] # => nil
|
|
154
|
+
def get(key)
|
|
155
|
+
n = find_node(key)
|
|
156
|
+
n == @nil_node ? nil : n.value
|
|
157
|
+
end
|
|
158
|
+
alias_method :[], :get
|
|
159
|
+
|
|
160
|
+
# Inserts or updates a key-value pair in the tree.
|
|
161
|
+
#
|
|
162
|
+
# If the key already exists and overwrite is true (default), the value is updated.
|
|
163
|
+
# If overwrite is false and the key exists, the operation returns nil without modification.
|
|
164
|
+
#
|
|
165
|
+
# @param key [Object] the key to insert (must implement <=>)
|
|
166
|
+
# @param value [Object] the value to associate with the key
|
|
167
|
+
# @param overwrite [Boolean] whether to overwrite existing keys (default: true)
|
|
168
|
+
# @return [Boolean, nil] true if inserted/updated, nil if key exists and overwrite is false
|
|
169
|
+
# @example
|
|
170
|
+
# tree = RBTree.new
|
|
171
|
+
# tree.insert(1, 'one') # => true
|
|
172
|
+
# tree.insert(1, 'ONE') # => true (overwrites)
|
|
173
|
+
# tree.insert(1, 'uno', overwrite: false) # => nil (no change)
|
|
174
|
+
# tree[2] = 'two' # using alias
|
|
175
|
+
def insert(key, value, overwrite: true)
|
|
176
|
+
y = @nil_node
|
|
177
|
+
x = @root
|
|
178
|
+
while x != @nil_node
|
|
179
|
+
y = x
|
|
180
|
+
cmp = key <=> x.key
|
|
181
|
+
if cmp == 0
|
|
182
|
+
return nil unless overwrite
|
|
183
|
+
x.value = value
|
|
184
|
+
return true
|
|
185
|
+
elsif cmp < 0
|
|
186
|
+
x = x.left
|
|
187
|
+
else
|
|
188
|
+
x = x.right
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
z = Node.new(key, value, Node::RED, @nil_node, @nil_node, @nil_node)
|
|
192
|
+
z.parent = y
|
|
193
|
+
if y == @nil_node
|
|
194
|
+
@root = z
|
|
195
|
+
elsif (key <=> y.key) < 0
|
|
196
|
+
y.left = z
|
|
197
|
+
else
|
|
198
|
+
y.right = z
|
|
199
|
+
end
|
|
200
|
+
z.left = @nil_node
|
|
201
|
+
z.right = @nil_node
|
|
202
|
+
z.color = Node::RED
|
|
203
|
+
insert_fixup(z)
|
|
204
|
+
@size += 1
|
|
205
|
+
|
|
206
|
+
if @min_node == @nil_node || (key <=> @min_node.key) < 0
|
|
207
|
+
@min_node = z
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
true
|
|
211
|
+
end
|
|
212
|
+
alias_method :[]=, :insert
|
|
213
|
+
|
|
214
|
+
# Deletes the key-value pair with the specified key.
|
|
215
|
+
#
|
|
216
|
+
# @param key [Object] the key to delete
|
|
217
|
+
# @return [Object, nil] the value associated with the deleted key, or nil if not found
|
|
218
|
+
# @example
|
|
219
|
+
# tree = RBTree.new({1 => 'one', 2 => 'two'})
|
|
220
|
+
# tree.delete(1) # => "one"
|
|
221
|
+
# tree.delete(3) # => nil
|
|
222
|
+
def delete(key)
|
|
223
|
+
value = delete_node(key)
|
|
224
|
+
return nil unless value
|
|
225
|
+
@size -= 1
|
|
226
|
+
value
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
# Removes all key-value pairs from the tree.
|
|
230
|
+
#
|
|
231
|
+
# @return [RBTree] self
|
|
232
|
+
def clear
|
|
233
|
+
@root = @nil_node
|
|
234
|
+
@min_node = @nil_node
|
|
235
|
+
@size = 0
|
|
236
|
+
self
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# Removes and returns the minimum key-value pair.
|
|
240
|
+
#
|
|
241
|
+
# @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
|
|
242
|
+
# @example
|
|
243
|
+
# tree = RBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
|
|
244
|
+
# tree.shift # => [1, "one"]
|
|
245
|
+
# tree.shift # => [2, "two"]
|
|
246
|
+
def shift
|
|
247
|
+
return nil if @min_node == @nil_node
|
|
248
|
+
result = [@min_node.key, @min_node.value]
|
|
249
|
+
delete(@min_node.key)
|
|
250
|
+
result
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
# Removes and returns the maximum key-value pair.
|
|
254
|
+
#
|
|
255
|
+
# @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
|
|
256
|
+
# @example
|
|
257
|
+
# tree = RBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
|
|
258
|
+
# tree.pop # => [3, "three"]
|
|
259
|
+
# tree.pop # => [2, "two"]
|
|
260
|
+
def pop
|
|
261
|
+
n = rightmost(@root)
|
|
262
|
+
return nil if n == @nil_node
|
|
263
|
+
result = [n.key, n.value]
|
|
264
|
+
delete(n.key)
|
|
265
|
+
result
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
# Iterates over all key-value pairs in ascending order of keys.
|
|
269
|
+
#
|
|
270
|
+
# @yield [key, value] each key-value pair in the tree
|
|
271
|
+
# @return [Enumerator, RBTree] an Enumerator if no block is given, self otherwise
|
|
272
|
+
# @example
|
|
273
|
+
# tree = RBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
|
|
274
|
+
# tree.each { |k, v| puts "#{k}: #{v}" }
|
|
275
|
+
# # Output:
|
|
276
|
+
# # 1: one
|
|
277
|
+
# # 2: two
|
|
278
|
+
# # 3: three
|
|
279
|
+
def each(&block)
|
|
280
|
+
return enum_for(:each) unless block_given?
|
|
281
|
+
traverse_asc(@root, &block)
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
# Iterates over all key-value pairs in descending order of keys.
|
|
285
|
+
#
|
|
286
|
+
# @yield [key, value] each key-value pair in the tree
|
|
287
|
+
# @return [Enumerator, RBTree] an Enumerator if no block is given, self otherwise
|
|
288
|
+
# @example
|
|
289
|
+
# tree = RBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
|
|
290
|
+
# tree.reverse_each { |k, v| puts "#{k}: #{v}" }
|
|
291
|
+
# # Output:
|
|
292
|
+
# # 3: three
|
|
293
|
+
# # 2: two
|
|
294
|
+
# # 1: one
|
|
295
|
+
def reverse_each(&block)
|
|
296
|
+
return enum_for(:reverse_each) unless block_given?
|
|
297
|
+
traverse_desc(@root, &block)
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
# Returns the minimum key-value pair without removing it.
|
|
301
|
+
#
|
|
302
|
+
# @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
|
|
303
|
+
# @example
|
|
304
|
+
# tree = RBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
|
|
305
|
+
# tree.min # => [1, "one"]
|
|
306
|
+
def min
|
|
307
|
+
@min_node == @nil_node ? nil : [@min_node.key, @min_node.value]
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
# Returns the maximum key-value pair without removing it.
|
|
311
|
+
#
|
|
312
|
+
# @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
|
|
313
|
+
# @example
|
|
314
|
+
# tree = RBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
|
|
315
|
+
# tree.max # => [3, "three"]
|
|
316
|
+
def max
|
|
317
|
+
n = rightmost(@root)
|
|
318
|
+
n == @nil_node ? nil : [n.key, n.value]
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
# Retrieves all key-value pairs with keys less than the specified key.
|
|
322
|
+
#
|
|
323
|
+
# @param key [Object] the upper bound (exclusive)
|
|
324
|
+
# @yield [key, value] each matching key-value pair (if block given)
|
|
325
|
+
# @return [Array<Array(Object, Object)>, RBTree] array of [key, value] pairs if no block, self otherwise
|
|
326
|
+
# @example
|
|
327
|
+
# tree = RBTree.new({1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four'})
|
|
328
|
+
# tree.lt(3) # => [[1, "one"], [2, "two"]]
|
|
329
|
+
# tree.lt(3) { |k, v| puts "#{k}: #{v}" } # prints pairs and returns tree
|
|
330
|
+
def lt(key, &block)
|
|
331
|
+
if block_given?
|
|
332
|
+
traverse_lt(@root, key, &block)
|
|
333
|
+
self
|
|
334
|
+
else
|
|
335
|
+
res = []
|
|
336
|
+
traverse_lt(@root, key) { |k, v| res << [k, v] }
|
|
337
|
+
res
|
|
338
|
+
end
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
# Retrieves all key-value pairs with keys less than or equal to the specified key.
|
|
342
|
+
#
|
|
343
|
+
# @param key [Object] the upper bound (inclusive)
|
|
344
|
+
# @yield [key, value] each matching key-value pair (if block given)
|
|
345
|
+
# @return [Array<Array(Object, Object)>, RBTree] array of [key, value] pairs if no block, self otherwise
|
|
346
|
+
# @example
|
|
347
|
+
# tree = RBTree.new({1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four'})
|
|
348
|
+
# tree.lte(3) # => [[1, "one"], [2, "two"], [3, "three"]]
|
|
349
|
+
def lte(key, &block)
|
|
350
|
+
if block_given?
|
|
351
|
+
traverse_lte(@root, key, &block)
|
|
352
|
+
self
|
|
353
|
+
else
|
|
354
|
+
res = []
|
|
355
|
+
traverse_lte(@root, key) { |k, v| res << [k, v] }
|
|
356
|
+
res
|
|
357
|
+
end
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
# Retrieves all key-value pairs with keys greater than the specified key.
|
|
361
|
+
#
|
|
362
|
+
# @param key [Object] the lower bound (exclusive)
|
|
363
|
+
# @yield [key, value] each matching key-value pair (if block given)
|
|
364
|
+
# @return [Array<Array(Object, Object)>, RBTree] array of [key, value] pairs if no block, self otherwise
|
|
365
|
+
# @example
|
|
366
|
+
# tree = RBTree.new({1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four'})
|
|
367
|
+
# tree.gt(2) # => [[3, "three"], [4, "four"]]
|
|
368
|
+
def gt(key, &block)
|
|
369
|
+
if block_given?
|
|
370
|
+
traverse_gt(@root, key, &block)
|
|
371
|
+
self
|
|
372
|
+
else
|
|
373
|
+
res = []
|
|
374
|
+
traverse_gt(@root, key) { |k, v| res << [k, v] }
|
|
375
|
+
res
|
|
376
|
+
end
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
# Retrieves all key-value pairs with keys greater than or equal to the specified key.
|
|
380
|
+
#
|
|
381
|
+
# @param key [Object] the lower bound (inclusive)
|
|
382
|
+
# @yield [key, value] each matching key-value pair (if block given)
|
|
383
|
+
# @return [Array<Array(Object, Object)>, RBTree] array of [key, value] pairs if no block, self otherwise
|
|
384
|
+
# @example
|
|
385
|
+
# tree = RBTree.new({1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four'})
|
|
386
|
+
# tree.gte(2) # => [[2, "two"], [3, "three"], [4, "four"]]
|
|
387
|
+
def gte(key, &block)
|
|
388
|
+
if block_given?
|
|
389
|
+
traverse_gte(@root, key, &block)
|
|
390
|
+
self
|
|
391
|
+
else
|
|
392
|
+
res = []
|
|
393
|
+
traverse_gte(@root, key) { |k, v| res << [k, v] }
|
|
394
|
+
res
|
|
395
|
+
end
|
|
396
|
+
end
|
|
397
|
+
|
|
398
|
+
# Retrieves all key-value pairs with keys within the specified range.
|
|
399
|
+
#
|
|
400
|
+
# @param min [Object] the lower bound
|
|
401
|
+
# @param max [Object] the upper bound
|
|
402
|
+
# @param include_min [Boolean] whether to include the lower bound (default: true)
|
|
403
|
+
# @param include_max [Boolean] whether to include the upper bound (default: true)
|
|
404
|
+
# @yield [key, value] each matching key-value pair (if block given)
|
|
405
|
+
# @return [Array<Array(Object, Object)>, RBTree] array of [key, value] pairs if no block, self otherwise
|
|
406
|
+
# @example
|
|
407
|
+
# tree = RBTree.new({1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four', 5 => 'five'})
|
|
408
|
+
# tree.between(2, 4) # => [[2, "two"], [3, "three"], [4, "four"]]
|
|
409
|
+
# tree.between(2, 4, include_min: false) # => [[3, "three"], [4, "four"]]
|
|
410
|
+
# tree.between(2, 4, include_max: false) # => [[2, "two"], [3, "three"]]
|
|
411
|
+
def between(min, max, include_min: true, include_max: true, &block)
|
|
412
|
+
if block_given?
|
|
413
|
+
traverse_between(@root, min, max, include_min, include_max, &block)
|
|
414
|
+
self
|
|
415
|
+
else
|
|
416
|
+
res = []
|
|
417
|
+
traverse_between(@root, min, max, include_min, include_max) { |k, v| res << [k, v] }
|
|
418
|
+
res
|
|
419
|
+
end
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
# Returns the key-value pair with the key closest to the given key.
|
|
423
|
+
#
|
|
424
|
+
# This method requires keys to be numeric or support subtraction and abs methods.
|
|
425
|
+
# If multiple keys have the same distance, the one with the smaller key is returned.
|
|
426
|
+
#
|
|
427
|
+
# @param key [Numeric] the target key
|
|
428
|
+
# @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
|
|
429
|
+
# @example
|
|
430
|
+
# tree = RBTree.new({1 => 'one', 5 => 'five', 10 => 'ten'})
|
|
431
|
+
# tree.nearest(4) # => [5, "five"]
|
|
432
|
+
# tree.nearest(7) # => [5, "five"]
|
|
433
|
+
# tree.nearest(8) # => [10, "ten"]
|
|
434
|
+
def nearest(key)
|
|
435
|
+
return nil unless key.respond_to?(:-)
|
|
436
|
+
n = find_nearest_node(key)
|
|
437
|
+
n == @nil_node ? nil : [n.key, n.value]
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
# Validates the red-black tree properties.
|
|
441
|
+
#
|
|
442
|
+
# Checks that:
|
|
443
|
+
# 1. Root is black
|
|
444
|
+
# 2. All paths from root to leaves have the same number of black nodes
|
|
445
|
+
# 3. No red node has a red child
|
|
446
|
+
# 4. Keys are properly ordered
|
|
447
|
+
#
|
|
448
|
+
# @return [Boolean] true if all properties are satisfied, false otherwise
|
|
449
|
+
def valid?
|
|
450
|
+
return false if @root.color == Node::RED
|
|
451
|
+
return false if check_black_height(@root) == -1
|
|
452
|
+
return false unless check_order(@root)
|
|
453
|
+
true
|
|
454
|
+
end
|
|
455
|
+
|
|
456
|
+
# @!visibility private
|
|
457
|
+
private
|
|
458
|
+
|
|
459
|
+
# Traverses the tree in ascending order (in-order traversal).
|
|
460
|
+
#
|
|
461
|
+
# @param node [Node] the current node
|
|
462
|
+
# @yield [key, value] each key-value pair in ascending order
|
|
463
|
+
# @return [void]
|
|
464
|
+
def traverse_asc(node, &block)
|
|
465
|
+
return if node == @nil_node
|
|
466
|
+
traverse_asc(node.left, &block)
|
|
467
|
+
yield node.key, node.value
|
|
468
|
+
traverse_asc(node.right, &block)
|
|
469
|
+
end
|
|
470
|
+
|
|
471
|
+
# Traverses the tree in descending order (reverse in-order traversal).
|
|
472
|
+
#
|
|
473
|
+
# @param node [Node] the current node
|
|
474
|
+
# @yield [key, value] each key-value pair in descending order
|
|
475
|
+
# @return [void]
|
|
476
|
+
def traverse_desc(node, &block)
|
|
477
|
+
return if node == @nil_node
|
|
478
|
+
traverse_desc(node.right, &block)
|
|
479
|
+
yield node.key, node.value
|
|
480
|
+
traverse_desc(node.left, &block)
|
|
481
|
+
end
|
|
482
|
+
|
|
483
|
+
# Traverses nodes with keys less than the specified key.
|
|
484
|
+
#
|
|
485
|
+
# @param node [Node] the current node
|
|
486
|
+
# @param key [Object] the upper bound (exclusive)
|
|
487
|
+
# @yield [key, value] each matching key-value pair
|
|
488
|
+
# @return [void]
|
|
489
|
+
def traverse_lt(node, key, &block)
|
|
490
|
+
return if node == @nil_node
|
|
491
|
+
|
|
492
|
+
traverse_lt(node.left, key, &block)
|
|
493
|
+
if (node.key <=> key) < 0
|
|
494
|
+
yield node.key, node.value
|
|
495
|
+
traverse_lt(node.right, key, &block)
|
|
496
|
+
end
|
|
497
|
+
end
|
|
498
|
+
|
|
499
|
+
# Traverses nodes with keys less than or equal to the specified key.
|
|
500
|
+
#
|
|
501
|
+
# @param node [Node] the current node
|
|
502
|
+
# @param key [Object] the upper bound (inclusive)
|
|
503
|
+
# @yield [key, value] each matching key-value pair
|
|
504
|
+
# @return [void]
|
|
505
|
+
def traverse_lte(node, key, &block)
|
|
506
|
+
return if node == @nil_node
|
|
507
|
+
|
|
508
|
+
traverse_lte(node.left, key, &block)
|
|
509
|
+
if (node.key <=> key) <= 0
|
|
510
|
+
yield node.key, node.value
|
|
511
|
+
traverse_lte(node.right, key, &block)
|
|
512
|
+
end
|
|
513
|
+
end
|
|
514
|
+
|
|
515
|
+
# Traverses nodes with keys greater than the specified key.
|
|
516
|
+
#
|
|
517
|
+
# @param node [Node] the current node
|
|
518
|
+
# @param key [Object] the lower bound (exclusive)
|
|
519
|
+
# @yield [key, value] each matching key-value pair
|
|
520
|
+
# @return [void]
|
|
521
|
+
def traverse_gt(node, key, &block)
|
|
522
|
+
return if node == @nil_node
|
|
523
|
+
|
|
524
|
+
if (node.key <=> key) > 0
|
|
525
|
+
traverse_gt(node.left, key, &block)
|
|
526
|
+
yield node.key, node.value
|
|
527
|
+
end
|
|
528
|
+
traverse_gt(node.right, key, &block)
|
|
529
|
+
end
|
|
530
|
+
|
|
531
|
+
# Traverses nodes with keys greater than or equal to the specified key.
|
|
532
|
+
#
|
|
533
|
+
# @param node [Node] the current node
|
|
534
|
+
# @param key [Object] the lower bound (inclusive)
|
|
535
|
+
# @yield [key, value] each matching key-value pair
|
|
536
|
+
# @return [void]
|
|
537
|
+
def traverse_gte(node, key, &block)
|
|
538
|
+
return if node == @nil_node
|
|
539
|
+
|
|
540
|
+
if (node.key <=> key) >= 0
|
|
541
|
+
traverse_gte(node.left, key, &block)
|
|
542
|
+
yield node.key, node.value
|
|
543
|
+
end
|
|
544
|
+
traverse_gte(node.right, key, &block)
|
|
545
|
+
end
|
|
546
|
+
|
|
547
|
+
# Traverses nodes with keys within the specified range.
|
|
548
|
+
#
|
|
549
|
+
# @param node [Node] the current node
|
|
550
|
+
# @param min [Object] the lower bound
|
|
551
|
+
# @param max [Object] the upper bound
|
|
552
|
+
# @param include_min [Boolean] whether to include the lower bound
|
|
553
|
+
# @param include_max [Boolean] whether to include the upper bound
|
|
554
|
+
# @yield [key, value] each matching key-value pair
|
|
555
|
+
# @return [void]
|
|
556
|
+
def traverse_between(node, min, max, include_min, include_max, &block)
|
|
557
|
+
return if node == @nil_node
|
|
558
|
+
if (node.key <=> min) > 0
|
|
559
|
+
traverse_between(node.left, min, max, include_min, include_max, &block)
|
|
560
|
+
end
|
|
561
|
+
|
|
562
|
+
greater = include_min ? (node.key <=> min) >= 0 : (node.key <=> min) > 0
|
|
563
|
+
less = include_max ? (node.key <=> max) <= 0 : (node.key <=> max) < 0
|
|
564
|
+
|
|
565
|
+
if greater && less
|
|
566
|
+
yield node.key, node.value
|
|
567
|
+
end
|
|
568
|
+
|
|
569
|
+
if (node.key <=> max) < 0
|
|
570
|
+
traverse_between(node.right, min, max, include_min, include_max, &block)
|
|
571
|
+
end
|
|
572
|
+
end
|
|
573
|
+
|
|
574
|
+
# Restores red-black tree properties after insertion.
|
|
575
|
+
#
|
|
576
|
+
# This method fixes any violations of red-black properties that may occur
|
|
577
|
+
# after inserting a new node (which is always colored red).
|
|
578
|
+
#
|
|
579
|
+
# @param z [Node] the newly inserted node
|
|
580
|
+
# @return [void]
|
|
581
|
+
def insert_fixup(z)
|
|
582
|
+
while z.parent.color == Node::RED
|
|
583
|
+
if z.parent == z.parent.parent.left
|
|
584
|
+
y = z.parent.parent.right
|
|
585
|
+
if y.color == Node::RED
|
|
586
|
+
z.parent.color = Node::BLACK
|
|
587
|
+
y.color = Node::BLACK
|
|
588
|
+
z.parent.parent.color = Node::RED
|
|
589
|
+
z = z.parent.parent
|
|
590
|
+
else
|
|
591
|
+
if z == z.parent.right
|
|
592
|
+
z = z.parent
|
|
593
|
+
left_rotate(z)
|
|
594
|
+
end
|
|
595
|
+
z.parent.color = Node::BLACK
|
|
596
|
+
z.parent.parent.color = Node::RED
|
|
597
|
+
right_rotate(z.parent.parent)
|
|
598
|
+
end
|
|
599
|
+
else
|
|
600
|
+
y = z.parent.parent.left
|
|
601
|
+
if y.color == Node::RED
|
|
602
|
+
z.parent.color = Node::BLACK
|
|
603
|
+
y.color = Node::BLACK
|
|
604
|
+
z.parent.parent.color = Node::RED
|
|
605
|
+
z = z.parent.parent
|
|
606
|
+
else
|
|
607
|
+
if z == z.parent.left
|
|
608
|
+
z = z.parent
|
|
609
|
+
right_rotate(z)
|
|
610
|
+
end
|
|
611
|
+
z.parent.color = Node::BLACK
|
|
612
|
+
z.parent.parent.color = Node::RED
|
|
613
|
+
left_rotate(z.parent.parent)
|
|
614
|
+
end
|
|
615
|
+
end
|
|
616
|
+
end
|
|
617
|
+
@root.color = Node::BLACK
|
|
618
|
+
end
|
|
619
|
+
|
|
620
|
+
# Finds and removes a node by key, returning its value.
|
|
621
|
+
#
|
|
622
|
+
# @param key [Object] the key to delete
|
|
623
|
+
# @return [Object, nil] the value of the deleted node, or nil if not found
|
|
624
|
+
def delete_node(key)
|
|
625
|
+
z = find_node(key)
|
|
626
|
+
return nil if z == @nil_node
|
|
627
|
+
remove_node(z)
|
|
628
|
+
end
|
|
629
|
+
|
|
630
|
+
# Removes a node from the tree and restores red-black properties.
|
|
631
|
+
#
|
|
632
|
+
# Handles three cases:
|
|
633
|
+
# 1. Node has no left child
|
|
634
|
+
# 2. Node has no right child
|
|
635
|
+
# 3. Node has both children (replace with inorder successor)
|
|
636
|
+
#
|
|
637
|
+
# @param z [Node] the node to remove
|
|
638
|
+
# @return [Object] the value of the removed node
|
|
639
|
+
def remove_node(z)
|
|
640
|
+
next_min_node = nil
|
|
641
|
+
if z == @min_node
|
|
642
|
+
if z.right != @nil_node
|
|
643
|
+
next_min_node = leftmost(z.right)
|
|
644
|
+
else
|
|
645
|
+
next_min_node = z.parent
|
|
646
|
+
end
|
|
647
|
+
end
|
|
648
|
+
|
|
649
|
+
y = z
|
|
650
|
+
y_original_color = y.color
|
|
651
|
+
if z.left == @nil_node
|
|
652
|
+
x = z.right
|
|
653
|
+
transplant(z, z.right)
|
|
654
|
+
elsif z.right == @nil_node
|
|
655
|
+
x = z.left
|
|
656
|
+
transplant(z, z.left)
|
|
657
|
+
else
|
|
658
|
+
y = leftmost(z.right)
|
|
659
|
+
y_original_color = y.color
|
|
660
|
+
x = y.right
|
|
661
|
+
if y.parent == z
|
|
662
|
+
x.parent = y
|
|
663
|
+
else
|
|
664
|
+
transplant(y, y.right)
|
|
665
|
+
y.right = z.right
|
|
666
|
+
y.right.parent = y
|
|
667
|
+
end
|
|
668
|
+
transplant(z, y)
|
|
669
|
+
y.left = z.left
|
|
670
|
+
y.left.parent = y
|
|
671
|
+
y.color = z.color
|
|
672
|
+
end
|
|
673
|
+
if y_original_color == Node::BLACK
|
|
674
|
+
delete_fixup(x)
|
|
675
|
+
end
|
|
676
|
+
|
|
677
|
+
if next_min_node
|
|
678
|
+
@min_node = next_min_node
|
|
679
|
+
end
|
|
680
|
+
|
|
681
|
+
z.value
|
|
682
|
+
end
|
|
683
|
+
|
|
684
|
+
# Restores red-black tree properties after deletion.
|
|
685
|
+
#
|
|
686
|
+
# This method fixes any violations of red-black properties that may occur
|
|
687
|
+
# after removing a black node from the tree.
|
|
688
|
+
#
|
|
689
|
+
# @param x [Node] the node that needs rebalancing
|
|
690
|
+
# @return [void]
|
|
691
|
+
def delete_fixup(x)
|
|
692
|
+
while x != @root && x.color == Node::BLACK
|
|
693
|
+
if x == x.parent.left
|
|
694
|
+
w = x.parent.right
|
|
695
|
+
if w.color == Node::RED
|
|
696
|
+
w.color = Node::BLACK
|
|
697
|
+
x.parent.color = Node::RED
|
|
698
|
+
left_rotate(x.parent)
|
|
699
|
+
w = x.parent.right
|
|
700
|
+
end
|
|
701
|
+
if w.left.color == Node::BLACK && w.right.color == Node::BLACK
|
|
702
|
+
w.color = Node::RED
|
|
703
|
+
x = x.parent
|
|
704
|
+
else
|
|
705
|
+
if w.right.color == Node::BLACK
|
|
706
|
+
w.left.color = Node::BLACK
|
|
707
|
+
w.color = Node::RED
|
|
708
|
+
right_rotate(w)
|
|
709
|
+
w = x.parent.right
|
|
710
|
+
end
|
|
711
|
+
w.color = x.parent.color
|
|
712
|
+
x.parent.color = Node::BLACK
|
|
713
|
+
w.right.color = Node::BLACK
|
|
714
|
+
left_rotate(x.parent)
|
|
715
|
+
x = @root
|
|
716
|
+
end
|
|
717
|
+
else
|
|
718
|
+
w = x.parent.left
|
|
719
|
+
if w.color == Node::RED
|
|
720
|
+
w.color = Node::BLACK
|
|
721
|
+
x.parent.color = Node::RED
|
|
722
|
+
right_rotate(x.parent)
|
|
723
|
+
w = x.parent.left
|
|
724
|
+
end
|
|
725
|
+
if w.right.color == Node::BLACK && w.left.color == Node::BLACK
|
|
726
|
+
w.color = Node::RED
|
|
727
|
+
x = x.parent
|
|
728
|
+
else
|
|
729
|
+
if w.left.color == Node::BLACK
|
|
730
|
+
w.right.color = Node::BLACK
|
|
731
|
+
w.color = Node::RED
|
|
732
|
+
left_rotate(w)
|
|
733
|
+
w = x.parent.left
|
|
734
|
+
end
|
|
735
|
+
w.color = x.parent.color
|
|
736
|
+
x.parent.color = Node::BLACK
|
|
737
|
+
w.left.color = Node::BLACK
|
|
738
|
+
right_rotate(x.parent)
|
|
739
|
+
x = @root
|
|
740
|
+
end
|
|
741
|
+
end
|
|
742
|
+
end
|
|
743
|
+
x.color = Node::BLACK
|
|
744
|
+
end
|
|
745
|
+
|
|
746
|
+
# Replaces subtree rooted at node u with subtree rooted at node v.
|
|
747
|
+
#
|
|
748
|
+
# @param u [Node] the node to be replaced
|
|
749
|
+
# @param v [Node] the replacement node
|
|
750
|
+
# @return [void]
|
|
751
|
+
def transplant(u, v)
|
|
752
|
+
if u.parent == @nil_node
|
|
753
|
+
@root = v
|
|
754
|
+
elsif u == u.parent.left
|
|
755
|
+
u.parent.left = v
|
|
756
|
+
else
|
|
757
|
+
u.parent.right = v
|
|
758
|
+
end
|
|
759
|
+
v.parent = u.parent
|
|
760
|
+
end
|
|
761
|
+
|
|
762
|
+
# Searches for a node with the given key.
|
|
763
|
+
#
|
|
764
|
+
# @param key [Object] the key to search for
|
|
765
|
+
# @return [Node] the found node, or @nil_node if not found
|
|
766
|
+
def find_node(key)
|
|
767
|
+
current = @root
|
|
768
|
+
while current != @nil_node
|
|
769
|
+
cmp = key <=> current.key
|
|
770
|
+
if cmp == 0
|
|
771
|
+
return current
|
|
772
|
+
elsif cmp < 0
|
|
773
|
+
current = current.left
|
|
774
|
+
else
|
|
775
|
+
current = current.right
|
|
776
|
+
end
|
|
777
|
+
end
|
|
778
|
+
@nil_node
|
|
779
|
+
end
|
|
780
|
+
|
|
781
|
+
# Finds the node with the closest key to the given key.
|
|
782
|
+
#
|
|
783
|
+
# Uses numeric distance (absolute difference) to determine proximity.
|
|
784
|
+
# If multiple nodes have the same distance, returns the one with the smaller key.
|
|
785
|
+
#
|
|
786
|
+
# @param key [Numeric] the target key
|
|
787
|
+
# @return [Node] the nearest node, or @nil_node if tree is empty
|
|
788
|
+
def find_nearest_node(key)
|
|
789
|
+
current = @root
|
|
790
|
+
closest = @nil_node
|
|
791
|
+
min_dist = nil
|
|
792
|
+
|
|
793
|
+
while current != @nil_node
|
|
794
|
+
cmp = key <=> current.key
|
|
795
|
+
if cmp == 0
|
|
796
|
+
return current
|
|
797
|
+
end
|
|
798
|
+
|
|
799
|
+
# For nearest, we still typically rely on numeric distance.
|
|
800
|
+
# If keys are strings, this part will fail unless they support -.
|
|
801
|
+
dist = (current.key - key).abs
|
|
802
|
+
|
|
803
|
+
if closest == @nil_node || dist < min_dist
|
|
804
|
+
min_dist = dist
|
|
805
|
+
closest = current
|
|
806
|
+
elsif dist == min_dist
|
|
807
|
+
if (current.key <=> closest.key) < 0
|
|
808
|
+
closest = current
|
|
809
|
+
end
|
|
810
|
+
end
|
|
811
|
+
|
|
812
|
+
if cmp < 0
|
|
813
|
+
current = current.left
|
|
814
|
+
else
|
|
815
|
+
current = current.right
|
|
816
|
+
end
|
|
817
|
+
end
|
|
818
|
+
closest
|
|
819
|
+
end
|
|
820
|
+
|
|
821
|
+
# Finds the leftmost (minimum) node in a subtree.
|
|
822
|
+
#
|
|
823
|
+
# @param node [Node] the root of the subtree
|
|
824
|
+
# @return [Node] the leftmost node
|
|
825
|
+
def leftmost(node)
|
|
826
|
+
while node.left != @nil_node
|
|
827
|
+
node = node.left
|
|
828
|
+
end
|
|
829
|
+
node
|
|
830
|
+
end
|
|
831
|
+
|
|
832
|
+
# Finds the rightmost (maximum) node in a subtree.
|
|
833
|
+
#
|
|
834
|
+
# @param node [Node] the root of the subtree
|
|
835
|
+
# @return [Node] the rightmost node
|
|
836
|
+
def rightmost(node)
|
|
837
|
+
while node.right != @nil_node
|
|
838
|
+
node = node.right
|
|
839
|
+
end
|
|
840
|
+
node
|
|
841
|
+
end
|
|
842
|
+
|
|
843
|
+
# Performs a left rotation on the given node.
|
|
844
|
+
#
|
|
845
|
+
# Transforms the tree structure:
|
|
846
|
+
# x y
|
|
847
|
+
# / \ / \
|
|
848
|
+
# a y => x c
|
|
849
|
+
# / \ / \
|
|
850
|
+
# b c a b
|
|
851
|
+
#
|
|
852
|
+
# @param x [Node] the node to rotate
|
|
853
|
+
# @return [void]
|
|
854
|
+
def left_rotate(x)
|
|
855
|
+
y = x.right
|
|
856
|
+
x.right = y.left
|
|
857
|
+
if y.left != @nil_node
|
|
858
|
+
y.left.parent = x
|
|
859
|
+
end
|
|
860
|
+
y.parent = x.parent
|
|
861
|
+
if x.parent == @nil_node
|
|
862
|
+
@root = y
|
|
863
|
+
elsif x == x.parent.left
|
|
864
|
+
x.parent.left = y
|
|
865
|
+
else
|
|
866
|
+
x.parent.right = y
|
|
867
|
+
end
|
|
868
|
+
y.left = x
|
|
869
|
+
x.parent = y
|
|
870
|
+
end
|
|
871
|
+
|
|
872
|
+
# Performs a right rotation on the given node.
|
|
873
|
+
#
|
|
874
|
+
# Transforms the tree structure:
|
|
875
|
+
# y x
|
|
876
|
+
# / \ / \
|
|
877
|
+
# x c => a y
|
|
878
|
+
# / \ / \
|
|
879
|
+
# a b b c
|
|
880
|
+
#
|
|
881
|
+
# @param y [Node] the node to rotate
|
|
882
|
+
# @return [void]
|
|
883
|
+
def right_rotate(y)
|
|
884
|
+
x = y.left
|
|
885
|
+
y.left = x.right
|
|
886
|
+
if x.right != @nil_node
|
|
887
|
+
x.right.parent = y
|
|
888
|
+
end
|
|
889
|
+
x.parent = y.parent
|
|
890
|
+
if y.parent == @nil_node
|
|
891
|
+
@root = x
|
|
892
|
+
elsif y == y.parent.right
|
|
893
|
+
y.parent.right = x
|
|
894
|
+
else
|
|
895
|
+
y.parent.left = x
|
|
896
|
+
end
|
|
897
|
+
x.right = y
|
|
898
|
+
y.parent = x
|
|
899
|
+
end
|
|
900
|
+
|
|
901
|
+
# Recursively checks black height consistency.
|
|
902
|
+
#
|
|
903
|
+
# Verifies that:
|
|
904
|
+
# - No red node has a red child
|
|
905
|
+
# - All paths have the same black height
|
|
906
|
+
#
|
|
907
|
+
# @param node [Node] the current node
|
|
908
|
+
# @return [Integer] the black height, or -1 if invalid
|
|
909
|
+
def check_black_height(node)
|
|
910
|
+
return 0 if node == @nil_node
|
|
911
|
+
|
|
912
|
+
if node.color == Node::RED
|
|
913
|
+
return -1 if node.left.color == Node::RED || node.right.color == Node::RED
|
|
914
|
+
end
|
|
915
|
+
|
|
916
|
+
left_h = check_black_height(node.left)
|
|
917
|
+
right_h = check_black_height(node.right)
|
|
918
|
+
|
|
919
|
+
return -1 if left_h == -1 || right_h == -1 || left_h != right_h
|
|
920
|
+
|
|
921
|
+
left_h + (node.color == Node::BLACK ? 1 : 0)
|
|
922
|
+
end
|
|
923
|
+
|
|
924
|
+
def check_order(node)
|
|
925
|
+
return true if node == @nil_node
|
|
926
|
+
if node.left != @nil_node && (node.left.key <=> node.key) >= 0
|
|
927
|
+
return false
|
|
928
|
+
end
|
|
929
|
+
if node.right != @nil_node && (node.right.key <=> node.key) <= 0
|
|
930
|
+
return false
|
|
931
|
+
end
|
|
932
|
+
check_order(node.left) && check_order(node.right)
|
|
933
|
+
end
|
|
934
|
+
end
|
|
935
|
+
|
|
936
|
+
# A Multi Red-Black Tree that allows duplicate keys.
|
|
937
|
+
#
|
|
938
|
+
# MultiRBTree extends RBTree to support multiple values per key. Each key maps to
|
|
939
|
+
# a linked list of values rather than a single value. The size reflects the total
|
|
940
|
+
# number of key-value pairs (not unique keys).
|
|
941
|
+
#
|
|
942
|
+
# == Features
|
|
943
|
+
#
|
|
944
|
+
# * Multiple values per key using linked lists
|
|
945
|
+
# * Separate methods for single deletion (`delete_one`) vs. all deletions (`delete`)
|
|
946
|
+
# * Values for each key maintain insertion order
|
|
947
|
+
# * min/max return first/last values respectively
|
|
948
|
+
#
|
|
949
|
+
# == Usage
|
|
950
|
+
#
|
|
951
|
+
# tree = MultiRBTree.new
|
|
952
|
+
# tree.insert(1, 'first one')
|
|
953
|
+
# tree.insert(1, 'second one')
|
|
954
|
+
# tree.insert(2, 'two')
|
|
955
|
+
#
|
|
956
|
+
# tree.size # => 3 (total key-value pairs)
|
|
957
|
+
# tree.get(1) # => "first one" (first value)
|
|
958
|
+
# tree.get_all(1) # => ["first one", "second one"] (all values)
|
|
959
|
+
#
|
|
960
|
+
# tree.delete_one(1) # removes only "first one"
|
|
961
|
+
# tree.get(1) # => "second one"
|
|
962
|
+
#
|
|
963
|
+
# tree.delete(1) # removes all remaining values for key 1
|
|
964
|
+
#
|
|
965
|
+
# @author Masahito Suzuki
|
|
966
|
+
# @since 0.1.2
|
|
967
|
+
class MultiRBTree < RBTree
|
|
968
|
+
# Retrieves the first value associated with the given key.
|
|
969
|
+
#
|
|
970
|
+
# @param key [Object] the key to look up
|
|
971
|
+
# @return [Object, nil] the first value for the key, or nil if not found
|
|
972
|
+
# @example
|
|
973
|
+
# tree = MultiRBTree.new
|
|
974
|
+
# tree.insert(1, 'first')
|
|
975
|
+
# tree.insert(1, 'second')
|
|
976
|
+
# tree.get(1) # => "first"
|
|
977
|
+
def get(key)
|
|
978
|
+
n = find_node(key)
|
|
979
|
+
n == @nil_node || n.value.empty? ? nil : n.value.first
|
|
980
|
+
end
|
|
981
|
+
alias_method :[], :get
|
|
982
|
+
|
|
983
|
+
# Retrieves all values associated with the given key.
|
|
984
|
+
#
|
|
985
|
+
# @param key [Object] the key to look up
|
|
986
|
+
# @return [Array, nil] an Array containing all values, or nil if not found
|
|
987
|
+
# @example
|
|
988
|
+
# tree = MultiRBTree.new
|
|
989
|
+
# tree.insert(1, 'first')
|
|
990
|
+
# tree.insert(1, 'second')
|
|
991
|
+
# tree.get_all(1).to_a # => ["first", "second"]
|
|
992
|
+
def get_all(key)
|
|
993
|
+
n = find_node(key)
|
|
994
|
+
n == @nil_node || n.value.empty? ? nil : n.value
|
|
995
|
+
end
|
|
996
|
+
|
|
997
|
+
# Inserts a value for the given key.
|
|
998
|
+
#
|
|
999
|
+
# If the key already exists, the value is appended to its list.
|
|
1000
|
+
# If the key doesn't exist, a new node is created.
|
|
1001
|
+
#
|
|
1002
|
+
# @param key [Object] the key (must implement <=>)
|
|
1003
|
+
# @param value [Object] the value to insert
|
|
1004
|
+
# @return [Boolean] always returns true
|
|
1005
|
+
# @example
|
|
1006
|
+
# tree = MultiRBTree.new
|
|
1007
|
+
# tree.insert(1, 'first')
|
|
1008
|
+
# tree.insert(1, 'second') # adds another value for key 1
|
|
1009
|
+
def insert(key, value)
|
|
1010
|
+
y = @nil_node
|
|
1011
|
+
x = @root
|
|
1012
|
+
while x != @nil_node
|
|
1013
|
+
y = x
|
|
1014
|
+
cmp = key <=> x.key
|
|
1015
|
+
if cmp == 0
|
|
1016
|
+
x.value << value
|
|
1017
|
+
@size += 1
|
|
1018
|
+
return true
|
|
1019
|
+
elsif cmp < 0
|
|
1020
|
+
x = x.left
|
|
1021
|
+
else
|
|
1022
|
+
x = x.right
|
|
1023
|
+
end
|
|
1024
|
+
end
|
|
1025
|
+
z = Node.new(key, [value], Node::RED, @nil_node, @nil_node, @nil_node)
|
|
1026
|
+
z.parent = y
|
|
1027
|
+
if y == @nil_node
|
|
1028
|
+
@root = z
|
|
1029
|
+
elsif (key <=> y.key) < 0
|
|
1030
|
+
y.left = z
|
|
1031
|
+
else
|
|
1032
|
+
y.right = z
|
|
1033
|
+
end
|
|
1034
|
+
z.left = @nil_node
|
|
1035
|
+
z.right = @nil_node
|
|
1036
|
+
z.color = Node::RED
|
|
1037
|
+
insert_fixup(z)
|
|
1038
|
+
@size += 1
|
|
1039
|
+
|
|
1040
|
+
if @min_node == @nil_node || (key <=> @min_node.key) < 0
|
|
1041
|
+
@min_node = z
|
|
1042
|
+
end
|
|
1043
|
+
|
|
1044
|
+
true
|
|
1045
|
+
end
|
|
1046
|
+
|
|
1047
|
+
# Deletes only the first value for the specified key.
|
|
1048
|
+
#
|
|
1049
|
+
# If the key has multiple values, removes only the first one.
|
|
1050
|
+
# If this was the last value for the key, the node is removed from the tree.
|
|
1051
|
+
#
|
|
1052
|
+
# @param key [Object] the key to delete from
|
|
1053
|
+
# @return [Object, nil] the deleted value, or nil if key not found
|
|
1054
|
+
# @example
|
|
1055
|
+
# tree = MultiRBTree.new
|
|
1056
|
+
# tree.insert(1, 'first')
|
|
1057
|
+
# tree.insert(1, 'second')
|
|
1058
|
+
# tree.delete_one(1) # => "first"
|
|
1059
|
+
# tree.get(1) # => "second"
|
|
1060
|
+
def delete_one(key)
|
|
1061
|
+
z = find_node(key)
|
|
1062
|
+
return nil if z == @nil_node
|
|
1063
|
+
|
|
1064
|
+
value = z.value.shift
|
|
1065
|
+
@size -= 1
|
|
1066
|
+
if z.value.empty?
|
|
1067
|
+
remove_node(z)
|
|
1068
|
+
end
|
|
1069
|
+
value
|
|
1070
|
+
end
|
|
1071
|
+
|
|
1072
|
+
# Deletes all values for the specified key.
|
|
1073
|
+
#
|
|
1074
|
+
# Removes the node and all associated values.
|
|
1075
|
+
#
|
|
1076
|
+
# @param key [Object] the key to delete
|
|
1077
|
+
# @return [Array, nil] the array of all deleted values, or nil if not found
|
|
1078
|
+
# @example
|
|
1079
|
+
# tree = MultiRBTree.new
|
|
1080
|
+
# tree.insert(1, 'first')
|
|
1081
|
+
# tree.insert(1, 'second')
|
|
1082
|
+
# vals = tree.delete(1) # removes both values
|
|
1083
|
+
# vals.size # => 2
|
|
1084
|
+
def delete(key)
|
|
1085
|
+
z = find_node(key)
|
|
1086
|
+
return nil if z == @nil_node
|
|
1087
|
+
|
|
1088
|
+
count = z.value.size
|
|
1089
|
+
remove_node(z)
|
|
1090
|
+
@size -= count
|
|
1091
|
+
z.value
|
|
1092
|
+
end
|
|
1093
|
+
|
|
1094
|
+
def shift
|
|
1095
|
+
return nil if @min_node == @nil_node
|
|
1096
|
+
node = @min_node
|
|
1097
|
+
key = node.key
|
|
1098
|
+
val = node.value.first
|
|
1099
|
+
node.value.shift
|
|
1100
|
+
@size -= 1
|
|
1101
|
+
if node.value.empty?
|
|
1102
|
+
remove_node(node)
|
|
1103
|
+
end
|
|
1104
|
+
[key, val]
|
|
1105
|
+
end
|
|
1106
|
+
|
|
1107
|
+
def pop
|
|
1108
|
+
n = rightmost(@root)
|
|
1109
|
+
return nil if n == @nil_node
|
|
1110
|
+
val = n.value.last
|
|
1111
|
+
n.value.pop
|
|
1112
|
+
@size -= 1
|
|
1113
|
+
if n.value.empty?
|
|
1114
|
+
remove_node(n)
|
|
1115
|
+
end
|
|
1116
|
+
[n.key, val]
|
|
1117
|
+
end
|
|
1118
|
+
|
|
1119
|
+
def min
|
|
1120
|
+
return nil if @min_node == @nil_node || @min_node.value.empty?
|
|
1121
|
+
[@min_node.key, @min_node.value.first]
|
|
1122
|
+
end
|
|
1123
|
+
|
|
1124
|
+
def max
|
|
1125
|
+
n = rightmost(@root)
|
|
1126
|
+
n == @nil_node || n.value.empty? ? nil : [n.key, n.value.first]
|
|
1127
|
+
end
|
|
1128
|
+
|
|
1129
|
+
def nearest(key)
|
|
1130
|
+
(n = super(key)) ? [n[0], n[1].first] : nil
|
|
1131
|
+
end
|
|
1132
|
+
|
|
1133
|
+
private
|
|
1134
|
+
|
|
1135
|
+
def traverse_asc(node, &block)
|
|
1136
|
+
return if node == @nil_node
|
|
1137
|
+
traverse_asc(node.left, &block)
|
|
1138
|
+
node.value.each { |v| yield node.key, v }
|
|
1139
|
+
traverse_asc(node.right, &block)
|
|
1140
|
+
end
|
|
1141
|
+
|
|
1142
|
+
def traverse_desc(node, &block)
|
|
1143
|
+
return if node == @nil_node
|
|
1144
|
+
traverse_desc(node.right, &block)
|
|
1145
|
+
node.value.reverse_each { |v| yield node.key, v }
|
|
1146
|
+
traverse_desc(node.left, &block)
|
|
1147
|
+
end
|
|
1148
|
+
|
|
1149
|
+
def traverse_lt(node, key, &block)
|
|
1150
|
+
return if node == @nil_node
|
|
1151
|
+
|
|
1152
|
+
traverse_lt(node.left, key, &block)
|
|
1153
|
+
if (node.key <=> key) < 0
|
|
1154
|
+
node.value.each { |v| yield node.key, v }
|
|
1155
|
+
traverse_lt(node.right, key, &block)
|
|
1156
|
+
end
|
|
1157
|
+
end
|
|
1158
|
+
|
|
1159
|
+
def traverse_lte(node, key, &block)
|
|
1160
|
+
return if node == @nil_node
|
|
1161
|
+
|
|
1162
|
+
traverse_lte(node.left, key, &block)
|
|
1163
|
+
if (node.key <=> key) <= 0
|
|
1164
|
+
node.value.each { |v| yield node.key, v }
|
|
1165
|
+
traverse_lte(node.right, key, &block)
|
|
1166
|
+
end
|
|
1167
|
+
end
|
|
1168
|
+
|
|
1169
|
+
def traverse_gt(node, key, &block)
|
|
1170
|
+
return if node == @nil_node
|
|
1171
|
+
|
|
1172
|
+
if (node.key <=> key) > 0
|
|
1173
|
+
traverse_gt(node.left, key, &block)
|
|
1174
|
+
node.value.each { |v| yield node.key, v }
|
|
1175
|
+
end
|
|
1176
|
+
traverse_gt(node.right, key, &block)
|
|
1177
|
+
end
|
|
1178
|
+
|
|
1179
|
+
def traverse_gte(node, key, &block)
|
|
1180
|
+
return if node == @nil_node
|
|
1181
|
+
|
|
1182
|
+
if (node.key <=> key) >= 0
|
|
1183
|
+
traverse_gte(node.left, key, &block)
|
|
1184
|
+
node.value.each { |v| yield node.key, v }
|
|
1185
|
+
end
|
|
1186
|
+
traverse_gte(node.right, key, &block)
|
|
1187
|
+
end
|
|
1188
|
+
|
|
1189
|
+
def traverse_between(node, min, max, include_min, include_max, &block)
|
|
1190
|
+
return if node == @nil_node
|
|
1191
|
+
if (node.key <=> min) > 0
|
|
1192
|
+
traverse_between(node.left, min, max, include_min, include_max, &block)
|
|
1193
|
+
end
|
|
1194
|
+
|
|
1195
|
+
greater = include_min ? (node.key <=> min) >= 0 : (node.key <=> min) > 0
|
|
1196
|
+
less = include_max ? (node.key <=> max) <= 0 : (node.key <=> max) < 0
|
|
1197
|
+
|
|
1198
|
+
if greater && less
|
|
1199
|
+
node.value.each { |v| yield node.key, v }
|
|
1200
|
+
end
|
|
1201
|
+
|
|
1202
|
+
if (node.key <=> max) < 0
|
|
1203
|
+
traverse_between(node.right, min, max, include_min, include_max, &block)
|
|
1204
|
+
end
|
|
1205
|
+
end
|
|
1206
|
+
end
|
|
1207
|
+
|
|
1208
|
+
# Internal node structure for RBTree.
|
|
1209
|
+
#
|
|
1210
|
+
# Each node stores a key-value pair, color (red or black), and references
|
|
1211
|
+
# to parent, left child, and right child nodes.
|
|
1212
|
+
#
|
|
1213
|
+
# @!attribute [rw] key
|
|
1214
|
+
# @return [Object] the key stored in this node
|
|
1215
|
+
# @!attribute [rw] value
|
|
1216
|
+
# @return [Object] the value stored in this node
|
|
1217
|
+
# @!attribute [rw] color
|
|
1218
|
+
# @return [Symbol] the color of the node (:red or :black)
|
|
1219
|
+
# @!attribute [rw] left
|
|
1220
|
+
# @return [Node] the left child node
|
|
1221
|
+
# @!attribute [rw] right
|
|
1222
|
+
# @return [Node] the right child node
|
|
1223
|
+
# @!attribute [rw] parent
|
|
1224
|
+
# @return [Node] the parent node
|
|
1225
|
+
#
|
|
1226
|
+
# @api private
|
|
1227
|
+
class RBTree::Node
|
|
1228
|
+
attr_accessor :key, :value, :color, :left, :right, :parent
|
|
1229
|
+
|
|
1230
|
+
# Red color constant
|
|
1231
|
+
RED = :red
|
|
1232
|
+
# Black color constant
|
|
1233
|
+
BLACK = :black
|
|
1234
|
+
|
|
1235
|
+
# Creates a new Node.
|
|
1236
|
+
#
|
|
1237
|
+
# @param key [Object] the key
|
|
1238
|
+
# @param value [Object] the value
|
|
1239
|
+
# @param color [Symbol] the color (:red or :black)
|
|
1240
|
+
# @param left [Node] the left child
|
|
1241
|
+
# @param right [Node] the right child
|
|
1242
|
+
# @param parent [Node] the parent node
|
|
1243
|
+
def initialize(key = nil, value = nil, color = BLACK, left = nil, right = nil, parent = nil)
|
|
1244
|
+
@key = key
|
|
1245
|
+
@value = value
|
|
1246
|
+
@color = color
|
|
1247
|
+
@left = left
|
|
1248
|
+
@right = right
|
|
1249
|
+
@parent = parent
|
|
1250
|
+
end
|
|
1251
|
+
|
|
1252
|
+
# Checks if the node is red.
|
|
1253
|
+
# @return [Boolean] true if red, false otherwise
|
|
1254
|
+
def red? = @color == RED
|
|
1255
|
+
|
|
1256
|
+
# Checks if the node is black.
|
|
1257
|
+
# @return [Boolean] true if black, false otherwise
|
|
1258
|
+
def black? = @color == BLACK
|
|
1259
|
+
end
|
|
1260
|
+
|