rbtree-ruby 0.2.0 → 0.2.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 +32 -0
- data/README.ja.md +10 -3
- data/README.md +10 -3
- data/lib/rbtree/version.rb +1 -1
- data/lib/rbtree.rb +354 -447
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 13b088e9f0f8ab5cf80a77b8f9b8e1af73b94b33bdff90115fe575def2c54b11
|
|
4
|
+
data.tar.gz: 51636a7c22c4ccc70d2ac14bafc58a39bbccac7599a704506c280d8d39345117
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e543801d0b22de4ee8654f7b8164121c2107ccda64bc16f47d034e98526703e4aa444e03cecd225bddb9aa9fc5547813bcd1bc73cd4a4048df98eee5d41a2fc6
|
|
7
|
+
data.tar.gz: 6d6986550fe2293e971558e65119f230c3eb26e8f43f8af77fe8bf666d5df337c6bf23e36a4e4fd7e8aee86287b6f58579e48a637e66d27a6e80ab66b0010ed4
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,38 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.2.2] - 2026-01-14
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
- **Iterative Traversal (Complete)**: All traversal methods (`lt`, `lte`, `gt`, `gte`, `between` and their `_desc` variants) now use an iterative stack-based approach instead of recursion.
|
|
12
|
+
- Ensures deep trees can be traversed without `SystemStackError`.
|
|
13
|
+
- Applies to both `RBTree` and `MultiRBTree`.
|
|
14
|
+
- **Code Deduplication**: Unified traversal logic between `RBTree` and `MultiRBTree` for better maintainability.
|
|
15
|
+
- **Documentation**: Minor typo fixes.
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
- **MultiRBTree#prev / #succ**: Fixed incorrect use of bare `super` which forwarded keyword arguments to parent methods that don't accept them. Also fixed incorrect access to parent return value (was treating `[key, value]` pair as a node object).
|
|
19
|
+
- **MultiRBTree#shift / #pop hash index leak**: When `shift` or `pop` removed the last value for a key, the key remained in the internal hash index (`@hash_index`). Now correctly uses `delete_node(key)` instead of `remove_node(node)` to ensure hash index consistency.
|
|
20
|
+
|
|
21
|
+
## [0.2.1] - 2026-01-14
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
- **Enhanced iteration**: `each` now accepts `reverse:` and `safe:` options
|
|
25
|
+
- `tree.each(reverse: true) { ... }` (same as `reverse_each`)
|
|
26
|
+
- `tree.each(safe: true) { ... }` (modification-safe)
|
|
27
|
+
- `tree.each(reverse: true, safe: true) { ... }` (reverse modification-safe)
|
|
28
|
+
- In `MultiRBTree`, `reverse: true` also iterates over values in reverse insertion order.
|
|
29
|
+
- **Range query safe mode**: `safe:` option for `lt`, `lte`, `gt`, `gte`, `between`
|
|
30
|
+
- `tree.lt(10, safe: true) { |k, _| tree.delete(k) if k.even? }`
|
|
31
|
+
- Works with `:reverse` option: `tree.gt(5, reverse: true, safe: true)`
|
|
32
|
+
- Returns Enumerator: `tree.between(1, 100, safe: true).select { ... }`
|
|
33
|
+
|
|
34
|
+
### Changed
|
|
35
|
+
- **MultiRBTree#get_all**: Now returns an `Enumerator` instead of an `Array` when no block is given.
|
|
36
|
+
- Improves consistency with other iteration methods.
|
|
37
|
+
- Safe handling for non-existent keys (returns empty Enumerator/nil logic handled safely).
|
|
38
|
+
- Use `.to_a` to get an Array: `tree.get_all(key).to_a`
|
|
39
|
+
|
|
8
40
|
## [0.2.0] - 2026-01-14
|
|
9
41
|
|
|
10
42
|
### Added
|
data/README.ja.md
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
🌍 *[English](README.md) | [日本語](README.ja.md)*
|
|
4
4
|
|
|
5
|
-
Red-Black Tree(赤黒木)データ構造のピュアRuby実装です。挿入、削除、検索操作がO(log n)
|
|
5
|
+
Red-Black Tree(赤黒木)データ構造のピュアRuby実装です。挿入、削除、検索操作がO(log n)の時間計算量で実行できる、
|
|
6
|
+
効率的な順序付きキーバリューストレージを提供します。
|
|
6
7
|
|
|
7
8
|
## 特徴
|
|
8
9
|
|
|
@@ -60,6 +61,12 @@ tree.each { |key, value| puts "#{key}: #{value}" }
|
|
|
60
61
|
# 10: ten
|
|
61
62
|
# 20: twenty
|
|
62
63
|
|
|
64
|
+
# イテレーション中の変更
|
|
65
|
+
# 標準のHashやArrayとは異なり、`safe: true`オプションを指定することで
|
|
66
|
+
# イテレーション中に安全にキーの削除や挿入を行うことができます。
|
|
67
|
+
tree.each(safe: true) { |k, v| tree.delete(k) if k.even? }
|
|
68
|
+
tree.each(reverse: true) { |k, v| puts k } # reverse_eachと同じ
|
|
69
|
+
|
|
63
70
|
# 最小値と最大値
|
|
64
71
|
tree.min # => [1, "one"]
|
|
65
72
|
tree.max # => [20, "twenty"]
|
|
@@ -100,8 +107,8 @@ tree.size # => 4 (キーバリューペアの総数)
|
|
|
100
107
|
tree.get(1) # => "first one"
|
|
101
108
|
tree[1] # => "first one"
|
|
102
109
|
|
|
103
|
-
#
|
|
104
|
-
tree.get_all(1) # => ["first one", "second one", "third one"]
|
|
110
|
+
# キーの全ての値を取得(Enumeratorを返す)
|
|
111
|
+
tree.get_all(1).to_a # => ["first one", "second one", "third one"]
|
|
105
112
|
|
|
106
113
|
# 全キーバリューペアをイテレーション
|
|
107
114
|
tree.each { |k, v| puts "#{k}: #{v}" }
|
data/README.md
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
🌍 *[English](README.md) | [日本語](README.ja.md)*
|
|
4
4
|
|
|
5
|
-
A pure Ruby implementation of the Red-Black Tree data structure, providing efficient ordered
|
|
5
|
+
A pure Ruby implementation of the Red-Black Tree data structure, providing efficient ordered
|
|
6
|
+
key-value storage with O(log n) time complexity for insertion, deletion, and lookup operations.
|
|
6
7
|
|
|
7
8
|
## Features
|
|
8
9
|
|
|
@@ -60,6 +61,12 @@ tree.each { |key, value| puts "#{key}: #{value}" }
|
|
|
60
61
|
# 10: ten
|
|
61
62
|
# 20: twenty
|
|
62
63
|
|
|
64
|
+
# Modification during iteration
|
|
65
|
+
# Unlike standard Ruby Hash/Array, modification during iteration is fully supported
|
|
66
|
+
# with the `safe: true` option. This allows you to delete or insert keys safely while iterating.
|
|
67
|
+
tree.each(safe: true) { |k, v| tree.delete(k) if k.even? }
|
|
68
|
+
tree.each(reverse: true) { |k, v| puts k } # Same as reverse_each
|
|
69
|
+
|
|
63
70
|
# Min and max
|
|
64
71
|
tree.min # => [1, "one"]
|
|
65
72
|
tree.max # => [20, "twenty"]
|
|
@@ -100,8 +107,8 @@ tree.size # => 4 (total number of key-value pairs)
|
|
|
100
107
|
tree.get(1) # => "first one"
|
|
101
108
|
tree[1] # => "first one"
|
|
102
109
|
|
|
103
|
-
# Get all values for a key
|
|
104
|
-
tree.get_all(1) # => ["first one", "second one", "third one"]
|
|
110
|
+
# Get all values for a key (returns Enumerator)
|
|
111
|
+
tree.get_all(1).to_a # => ["first one", "second one", "third one"]
|
|
105
112
|
|
|
106
113
|
# Iterate over all key-value pairs
|
|
107
114
|
tree.each { |k, v| puts "#{k}: #{v}" }
|
data/lib/rbtree/version.rb
CHANGED
data/lib/rbtree.rb
CHANGED
|
@@ -112,26 +112,27 @@ class RBTree
|
|
|
112
112
|
end
|
|
113
113
|
end
|
|
114
114
|
|
|
115
|
-
# Returns a string representation of the tree.
|
|
116
|
-
#
|
|
117
|
-
# Shows the first 5 entries and total size. Useful for debugging.
|
|
118
|
-
#
|
|
119
|
-
# @return [String] a human-readable representation of the tree
|
|
120
|
-
def inspect
|
|
121
|
-
if @size > 0
|
|
122
|
-
content = first(5).map { |k, v| "#{k.inspect}=>#{v.inspect}" }.join(", ")
|
|
123
|
-
suffix = @size > 5 ? ", ..." : ""
|
|
124
|
-
"#<#{self.class}:0x#{object_id.to_s(16)} size=#{@size} {#{content}#{suffix}}>"
|
|
125
|
-
else
|
|
126
|
-
super
|
|
127
|
-
end
|
|
128
|
-
end
|
|
129
|
-
|
|
130
115
|
# Checks if the tree is empty.
|
|
131
116
|
#
|
|
132
117
|
# @return [Boolean] true if the tree contains no elements, false otherwise
|
|
133
118
|
def empty? = @root == @nil_node
|
|
134
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
|
+
|
|
135
136
|
# Checks if the tree contains the given key.
|
|
136
137
|
#
|
|
137
138
|
# @param key [Object] the key to search for
|
|
@@ -158,6 +159,58 @@ class RBTree
|
|
|
158
159
|
end
|
|
159
160
|
alias_method :[], :get
|
|
160
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
|
+
|
|
161
214
|
# Inserts or updates a key-value pair in the tree.
|
|
162
215
|
#
|
|
163
216
|
# If the key already exists and overwrite is true (default), the value is updated.
|
|
@@ -233,17 +286,6 @@ class RBTree
|
|
|
233
286
|
value
|
|
234
287
|
end
|
|
235
288
|
|
|
236
|
-
# Removes all key-value pairs from the tree.
|
|
237
|
-
#
|
|
238
|
-
# @return [RBTree] self
|
|
239
|
-
def clear
|
|
240
|
-
@root = @nil_node
|
|
241
|
-
@min_node = @nil_node
|
|
242
|
-
@hash_index.clear
|
|
243
|
-
@size = 0
|
|
244
|
-
self
|
|
245
|
-
end
|
|
246
|
-
|
|
247
289
|
# Removes and returns the minimum key-value pair.
|
|
248
290
|
#
|
|
249
291
|
# @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
|
|
@@ -268,13 +310,26 @@ class RBTree
|
|
|
268
310
|
def pop
|
|
269
311
|
n = rightmost(@root)
|
|
270
312
|
return nil if n == @nil_node
|
|
271
|
-
result =
|
|
313
|
+
result = n.pair
|
|
272
314
|
delete(n.key)
|
|
273
315
|
result
|
|
274
316
|
end
|
|
275
317
|
|
|
276
|
-
#
|
|
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.
|
|
277
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)
|
|
278
333
|
# @yield [key, value] each key-value pair in the tree
|
|
279
334
|
# @return [Enumerator, RBTree] an Enumerator if no block is given, self otherwise
|
|
280
335
|
# @example
|
|
@@ -284,9 +339,22 @@ class RBTree
|
|
|
284
339
|
# # 1: one
|
|
285
340
|
# # 2: two
|
|
286
341
|
# # 3: three
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
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
|
|
290
358
|
end
|
|
291
359
|
|
|
292
360
|
# Iterates over all key-value pairs in descending order of keys.
|
|
@@ -300,49 +368,34 @@ class RBTree
|
|
|
300
368
|
# # 3: three
|
|
301
369
|
# # 2: two
|
|
302
370
|
# # 1: one
|
|
303
|
-
|
|
304
|
-
return enum_for(:reverse_each) unless block_given?
|
|
305
|
-
traverse_desc(@root, &block)
|
|
306
|
-
end
|
|
307
|
-
|
|
308
|
-
# Returns the minimum key-value pair without removing it.
|
|
371
|
+
# Iterates over all key-value pairs in descending order of keys.
|
|
309
372
|
#
|
|
310
|
-
#
|
|
311
|
-
# @example
|
|
312
|
-
# tree = RBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
|
|
313
|
-
# tree.min # => [1, "one"]
|
|
314
|
-
def min
|
|
315
|
-
@min_node == @nil_node ? nil : [@min_node.key, @min_node.value]
|
|
316
|
-
end
|
|
317
|
-
|
|
318
|
-
# Returns the maximum key-value pair without removing it.
|
|
373
|
+
# This is an alias for `each(reverse: true)`.
|
|
319
374
|
#
|
|
320
|
-
# @
|
|
321
|
-
# @
|
|
322
|
-
#
|
|
323
|
-
#
|
|
324
|
-
def
|
|
325
|
-
n = rightmost(@root)
|
|
326
|
-
n == @nil_node ? nil : [n.key, n.value]
|
|
327
|
-
end
|
|
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)
|
|
328
380
|
|
|
329
381
|
# Retrieves all key-value pairs with keys less than the specified key.
|
|
330
382
|
#
|
|
331
383
|
# @param key [Object] the upper bound (exclusive)
|
|
332
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)
|
|
333
386
|
# @yield [key, value] each matching key-value pair (if block given)
|
|
334
387
|
# @return [Enumerator, RBTree] Enumerator if no block given, self otherwise
|
|
335
388
|
# @example
|
|
336
389
|
# tree = RBTree.new({1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four'})
|
|
337
390
|
# tree.lt(3).to_a # => [[1, "one"], [2, "two"]]
|
|
338
391
|
# tree.lt(3, reverse: true).first # => [2, "two"]
|
|
339
|
-
# tree.lt(3) { |k,
|
|
340
|
-
def lt(key, reverse: false, &block)
|
|
341
|
-
return enum_for(:lt, key, reverse: reverse) unless block_given?
|
|
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?
|
|
342
395
|
if reverse
|
|
343
|
-
traverse_lt_desc(@root, key, &block)
|
|
396
|
+
traverse_lt_desc(@root, key, safe: safe, &block)
|
|
344
397
|
else
|
|
345
|
-
|
|
398
|
+
traverse_lt_asc(@root, key, safe: safe, &block)
|
|
346
399
|
end
|
|
347
400
|
self
|
|
348
401
|
end
|
|
@@ -351,18 +404,19 @@ class RBTree
|
|
|
351
404
|
#
|
|
352
405
|
# @param key [Object] the upper bound (inclusive)
|
|
353
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)
|
|
354
408
|
# @yield [key, value] each matching key-value pair (if block given)
|
|
355
409
|
# @return [Enumerator, RBTree] Enumerator if no block given, self otherwise
|
|
356
410
|
# @example
|
|
357
411
|
# tree = RBTree.new({1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four'})
|
|
358
412
|
# tree.lte(3).to_a # => [[1, "one"], [2, "two"], [3, "three"]]
|
|
359
413
|
# tree.lte(3, reverse: true).first # => [3, "three"]
|
|
360
|
-
def lte(key, reverse: false, &block)
|
|
361
|
-
return enum_for(:lte, key, reverse: reverse) unless block_given?
|
|
414
|
+
def lte(key, reverse: false, safe: false, &block)
|
|
415
|
+
return enum_for(:lte, key, reverse: reverse, safe: safe) unless block_given?
|
|
362
416
|
if reverse
|
|
363
|
-
traverse_lte_desc(@root, key, &block)
|
|
417
|
+
traverse_lte_desc(@root, key, safe: safe, &block)
|
|
364
418
|
else
|
|
365
|
-
|
|
419
|
+
traverse_lte_asc(@root, key, safe: safe, &block)
|
|
366
420
|
end
|
|
367
421
|
self
|
|
368
422
|
end
|
|
@@ -371,18 +425,19 @@ class RBTree
|
|
|
371
425
|
#
|
|
372
426
|
# @param key [Object] the lower bound (exclusive)
|
|
373
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)
|
|
374
429
|
# @yield [key, value] each matching key-value pair (if block given)
|
|
375
430
|
# @return [Enumerator, RBTree] Enumerator if no block given, self otherwise
|
|
376
431
|
# @example
|
|
377
432
|
# tree = RBTree.new({1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four'})
|
|
378
433
|
# tree.gt(2).to_a # => [[3, "three"], [4, "four"]]
|
|
379
434
|
# tree.gt(2, reverse: true).first # => [4, "four"]
|
|
380
|
-
def gt(key, reverse: false, &block)
|
|
381
|
-
return enum_for(:gt, key, reverse: reverse) unless block_given?
|
|
435
|
+
def gt(key, reverse: false, safe: false, &block)
|
|
436
|
+
return enum_for(:gt, key, reverse: reverse, safe: safe) unless block_given?
|
|
382
437
|
if reverse
|
|
383
|
-
traverse_gt_desc(@root, key, &block)
|
|
438
|
+
traverse_gt_desc(@root, key, safe: safe, &block)
|
|
384
439
|
else
|
|
385
|
-
|
|
440
|
+
traverse_gt_asc(@root, key, safe: safe, &block)
|
|
386
441
|
end
|
|
387
442
|
self
|
|
388
443
|
end
|
|
@@ -391,18 +446,19 @@ class RBTree
|
|
|
391
446
|
#
|
|
392
447
|
# @param key [Object] the lower bound (inclusive)
|
|
393
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)
|
|
394
450
|
# @yield [key, value] each matching key-value pair (if block given)
|
|
395
451
|
# @return [Enumerator, RBTree] Enumerator if no block given, self otherwise
|
|
396
452
|
# @example
|
|
397
453
|
# tree = RBTree.new({1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four'})
|
|
398
454
|
# tree.gte(2).to_a # => [[2, "two"], [3, "three"], [4, "four"]]
|
|
399
455
|
# tree.gte(2, reverse: true).first # => [4, "four"]
|
|
400
|
-
def gte(key, reverse: false, &block)
|
|
401
|
-
return enum_for(:gte, key, reverse: reverse) unless block_given?
|
|
456
|
+
def gte(key, reverse: false, safe: false, &block)
|
|
457
|
+
return enum_for(:gte, key, reverse: reverse, safe: safe) unless block_given?
|
|
402
458
|
if reverse
|
|
403
|
-
traverse_gte_desc(@root, key, &block)
|
|
459
|
+
traverse_gte_desc(@root, key, safe: safe, &block)
|
|
404
460
|
else
|
|
405
|
-
|
|
461
|
+
traverse_gte_asc(@root, key, safe: safe, &block)
|
|
406
462
|
end
|
|
407
463
|
self
|
|
408
464
|
end
|
|
@@ -414,72 +470,36 @@ class RBTree
|
|
|
414
470
|
# @param include_min [Boolean] whether to include the lower bound (default: true)
|
|
415
471
|
# @param include_max [Boolean] whether to include the upper bound (default: true)
|
|
416
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)
|
|
417
474
|
# @yield [key, value] each matching key-value pair (if block given)
|
|
418
475
|
# @return [Enumerator, RBTree] Enumerator if no block given, self otherwise
|
|
419
476
|
# @example
|
|
420
477
|
# tree = RBTree.new({1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four', 5 => 'five'})
|
|
421
478
|
# tree.between(2, 4).to_a # => [[2, "two"], [3, "three"], [4, "four"]]
|
|
422
479
|
# tree.between(2, 4, reverse: true).first # => [4, "four"]
|
|
423
|
-
def between(min, max, include_min: true, include_max: true, reverse: false, &block)
|
|
424
|
-
return enum_for(:between, min, max, include_min: include_min, include_max: include_max, reverse: reverse) unless block_given?
|
|
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?
|
|
425
482
|
if reverse
|
|
426
|
-
traverse_between_desc(@root, min, max, include_min, include_max, &block)
|
|
483
|
+
traverse_between_desc(@root, min, max, include_min, include_max, safe: safe, &block)
|
|
427
484
|
else
|
|
428
|
-
|
|
485
|
+
traverse_between_asc(@root, min, max, include_min, include_max, safe: safe, &block)
|
|
429
486
|
end
|
|
430
487
|
self
|
|
431
488
|
end
|
|
432
489
|
|
|
433
|
-
# Returns
|
|
434
|
-
#
|
|
435
|
-
# This method requires keys to be numeric or support subtraction and abs methods.
|
|
436
|
-
# If multiple keys have the same distance, the one with the smaller key is returned.
|
|
437
|
-
#
|
|
438
|
-
# @param key [Numeric] the target key
|
|
439
|
-
# @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
|
|
440
|
-
# @example
|
|
441
|
-
# tree = RBTree.new({1 => 'one', 5 => 'five', 10 => 'ten'})
|
|
442
|
-
# tree.nearest(4) # => [5, "five"]
|
|
443
|
-
# tree.nearest(7) # => [5, "five"]
|
|
444
|
-
# tree.nearest(8) # => [10, "ten"]
|
|
445
|
-
def nearest(key)
|
|
446
|
-
return nil unless key.respond_to?(:-)
|
|
447
|
-
n = find_nearest_node(key)
|
|
448
|
-
n == @nil_node ? nil : [n.key, n.value]
|
|
449
|
-
end
|
|
450
|
-
|
|
451
|
-
# Returns the key-value pair with the largest key that is smaller than the given key.
|
|
452
|
-
#
|
|
453
|
-
# If the key exists in the tree, returns the predecessor (previous element).
|
|
454
|
-
# If the key does not exist, returns the largest key-value pair with key < given key.
|
|
455
|
-
#
|
|
456
|
-
# @param key [Object] the reference key
|
|
457
|
-
# @return [Array(Object, Object), nil] a two-element array [key, value], or nil if no predecessor exists
|
|
458
|
-
# @example
|
|
459
|
-
# tree = RBTree.new({1 => 'one', 3 => 'three', 5 => 'five', 7 => 'seven'})
|
|
460
|
-
# tree.prev(5) # => [3, "three"]
|
|
461
|
-
# tree.prev(4) # => [3, "three"] (4 does not exist)
|
|
462
|
-
# tree.prev(1) # => nil (no predecessor)
|
|
463
|
-
def prev(key)
|
|
464
|
-
n = find_predecessor_node(key)
|
|
465
|
-
n == @nil_node ? nil : [n.key, n.value]
|
|
466
|
-
end
|
|
467
|
-
|
|
468
|
-
# Returns the key-value pair with the smallest key that is larger than the given key.
|
|
490
|
+
# Returns a string representation of the tree.
|
|
469
491
|
#
|
|
470
|
-
#
|
|
471
|
-
# If the key does not exist, returns the smallest key-value pair with key > given key.
|
|
492
|
+
# Shows the first 5 entries and total size. Useful for debugging.
|
|
472
493
|
#
|
|
473
|
-
# @
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
n == @nil_node ? nil : [n.key, n.value]
|
|
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
|
|
483
503
|
end
|
|
484
504
|
|
|
485
505
|
# Validates the red-black tree properties.
|
|
@@ -504,56 +524,141 @@ class RBTree
|
|
|
504
524
|
# Traverses the tree in ascending order (in-order traversal).
|
|
505
525
|
#
|
|
506
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
|
|
507
532
|
# @yield [key, value] each key-value pair in ascending order
|
|
508
533
|
# @return [void]
|
|
509
|
-
def
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
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
|
|
516
577
|
end
|
|
517
|
-
current = stack.pop
|
|
518
|
-
yield current.key, current.value
|
|
519
|
-
current = current.right
|
|
520
578
|
end
|
|
521
579
|
end
|
|
522
580
|
|
|
523
581
|
# Traverses the tree in descending order (reverse in-order traversal).
|
|
524
582
|
#
|
|
525
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
|
|
526
589
|
# @yield [key, value] each key-value pair in descending order
|
|
527
590
|
# @return [void]
|
|
528
|
-
def
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
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
|
|
535
634
|
end
|
|
536
|
-
current = stack.pop
|
|
537
|
-
yield current.key, current.value
|
|
538
|
-
current = current.left
|
|
539
635
|
end
|
|
540
636
|
end
|
|
541
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
|
+
|
|
542
654
|
# Traverses nodes with keys less than the specified key.
|
|
543
655
|
#
|
|
544
656
|
# @param node [Node] the current node
|
|
545
657
|
# @param key [Object] the upper bound (exclusive)
|
|
546
658
|
# @yield [key, value] each matching key-value pair
|
|
547
659
|
# @return [void]
|
|
548
|
-
def
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
traverse_lt(node.left, key, &block)
|
|
552
|
-
if (node.key <=> key) < 0
|
|
553
|
-
yield node.key, node.value
|
|
554
|
-
traverse_lt(node.right, key, &block)
|
|
555
|
-
end
|
|
556
|
-
end
|
|
660
|
+
def traverse_lt_asc(node, key, safe: false, &block) =
|
|
661
|
+
traverse_range_asc(node, nil, key, false, false, safe: safe, &block)
|
|
557
662
|
|
|
558
663
|
# Traverses nodes with keys less than or equal to the specified key.
|
|
559
664
|
#
|
|
@@ -561,15 +666,8 @@ class RBTree
|
|
|
561
666
|
# @param key [Object] the upper bound (inclusive)
|
|
562
667
|
# @yield [key, value] each matching key-value pair
|
|
563
668
|
# @return [void]
|
|
564
|
-
def
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
traverse_lte(node.left, key, &block)
|
|
568
|
-
if (node.key <=> key) <= 0
|
|
569
|
-
yield node.key, node.value
|
|
570
|
-
traverse_lte(node.right, key, &block)
|
|
571
|
-
end
|
|
572
|
-
end
|
|
669
|
+
def traverse_lte_asc(node, key, safe: false, &block) =
|
|
670
|
+
traverse_range_asc(node, nil, key, false, true, safe: safe, &block)
|
|
573
671
|
|
|
574
672
|
# Traverses nodes with keys greater than the specified key.
|
|
575
673
|
#
|
|
@@ -577,15 +675,8 @@ class RBTree
|
|
|
577
675
|
# @param key [Object] the lower bound (exclusive)
|
|
578
676
|
# @yield [key, value] each matching key-value pair
|
|
579
677
|
# @return [void]
|
|
580
|
-
def
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
if (node.key <=> key) > 0
|
|
584
|
-
traverse_gt(node.left, key, &block)
|
|
585
|
-
yield node.key, node.value
|
|
586
|
-
end
|
|
587
|
-
traverse_gt(node.right, key, &block)
|
|
588
|
-
end
|
|
678
|
+
def traverse_gt_asc(node, key, safe: false, &block) =
|
|
679
|
+
traverse_range_asc(node, key, nil, false, false, safe: safe, &block)
|
|
589
680
|
|
|
590
681
|
# Traverses nodes with keys greater than or equal to the specified key.
|
|
591
682
|
#
|
|
@@ -593,15 +684,8 @@ class RBTree
|
|
|
593
684
|
# @param key [Object] the lower bound (inclusive)
|
|
594
685
|
# @yield [key, value] each matching key-value pair
|
|
595
686
|
# @return [void]
|
|
596
|
-
def
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
if (node.key <=> key) >= 0
|
|
600
|
-
traverse_gte(node.left, key, &block)
|
|
601
|
-
yield node.key, node.value
|
|
602
|
-
end
|
|
603
|
-
traverse_gte(node.right, key, &block)
|
|
604
|
-
end
|
|
687
|
+
def traverse_gte_asc(node, key, safe: false, &block) =
|
|
688
|
+
traverse_range_asc(node, key, nil, true, false, safe: safe, &block)
|
|
605
689
|
|
|
606
690
|
# Traverses nodes with keys within the specified range.
|
|
607
691
|
#
|
|
@@ -612,23 +696,8 @@ class RBTree
|
|
|
612
696
|
# @param include_max [Boolean] whether to include the upper bound
|
|
613
697
|
# @yield [key, value] each matching key-value pair
|
|
614
698
|
# @return [void]
|
|
615
|
-
def
|
|
616
|
-
|
|
617
|
-
if (node.key <=> min) > 0
|
|
618
|
-
traverse_between(node.left, min, max, include_min, include_max, &block)
|
|
619
|
-
end
|
|
620
|
-
|
|
621
|
-
greater = include_min ? (node.key <=> min) >= 0 : (node.key <=> min) > 0
|
|
622
|
-
less = include_max ? (node.key <=> max) <= 0 : (node.key <=> max) < 0
|
|
623
|
-
|
|
624
|
-
if greater && less
|
|
625
|
-
yield node.key, node.value
|
|
626
|
-
end
|
|
627
|
-
|
|
628
|
-
if (node.key <=> max) < 0
|
|
629
|
-
traverse_between(node.right, min, max, include_min, include_max, &block)
|
|
630
|
-
end
|
|
631
|
-
end
|
|
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)
|
|
632
701
|
|
|
633
702
|
# Traverses nodes with keys less than the specified key in descending order.
|
|
634
703
|
#
|
|
@@ -636,15 +705,8 @@ class RBTree
|
|
|
636
705
|
# @param key [Object] the upper bound (exclusive)
|
|
637
706
|
# @yield [key, value] each matching key-value pair in descending order
|
|
638
707
|
# @return [void]
|
|
639
|
-
def traverse_lt_desc(node, key, &block)
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
if (node.key <=> key) < 0
|
|
643
|
-
traverse_lt_desc(node.right, key, &block)
|
|
644
|
-
yield node.key, node.value
|
|
645
|
-
end
|
|
646
|
-
traverse_lt_desc(node.left, key, &block)
|
|
647
|
-
end
|
|
708
|
+
def traverse_lt_desc(node, key, safe: false, &block) =
|
|
709
|
+
traverse_range_desc(node, nil, key, false, false, safe: safe, &block)
|
|
648
710
|
|
|
649
711
|
# Traverses nodes with keys less than or equal to the specified key in descending order.
|
|
650
712
|
#
|
|
@@ -652,15 +714,8 @@ class RBTree
|
|
|
652
714
|
# @param key [Object] the upper bound (inclusive)
|
|
653
715
|
# @yield [key, value] each matching key-value pair in descending order
|
|
654
716
|
# @return [void]
|
|
655
|
-
def traverse_lte_desc(node, key, &block)
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
if (node.key <=> key) <= 0
|
|
659
|
-
traverse_lte_desc(node.right, key, &block)
|
|
660
|
-
yield node.key, node.value
|
|
661
|
-
end
|
|
662
|
-
traverse_lte_desc(node.left, key, &block)
|
|
663
|
-
end
|
|
717
|
+
def traverse_lte_desc(node, key, safe: false, &block) =
|
|
718
|
+
traverse_range_desc(node, nil, key, false, true, safe: safe, &block)
|
|
664
719
|
|
|
665
720
|
# Traverses nodes with keys greater than the specified key in descending order.
|
|
666
721
|
#
|
|
@@ -668,15 +723,8 @@ class RBTree
|
|
|
668
723
|
# @param key [Object] the lower bound (exclusive)
|
|
669
724
|
# @yield [key, value] each matching key-value pair in descending order
|
|
670
725
|
# @return [void]
|
|
671
|
-
def traverse_gt_desc(node, key, &block)
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
traverse_gt_desc(node.right, key, &block)
|
|
675
|
-
if (node.key <=> key) > 0
|
|
676
|
-
yield node.key, node.value
|
|
677
|
-
traverse_gt_desc(node.left, key, &block)
|
|
678
|
-
end
|
|
679
|
-
end
|
|
726
|
+
def traverse_gt_desc(node, key, safe: false, &block) =
|
|
727
|
+
traverse_range_desc(node, key, nil, false, false, safe: safe, &block)
|
|
680
728
|
|
|
681
729
|
# Traverses nodes with keys greater than or equal to the specified key in descending order.
|
|
682
730
|
#
|
|
@@ -684,15 +732,8 @@ class RBTree
|
|
|
684
732
|
# @param key [Object] the lower bound (inclusive)
|
|
685
733
|
# @yield [key, value] each matching key-value pair in descending order
|
|
686
734
|
# @return [void]
|
|
687
|
-
def traverse_gte_desc(node, key, &block)
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
traverse_gte_desc(node.right, key, &block)
|
|
691
|
-
if (node.key <=> key) >= 0
|
|
692
|
-
yield node.key, node.value
|
|
693
|
-
traverse_gte_desc(node.left, key, &block)
|
|
694
|
-
end
|
|
695
|
-
end
|
|
735
|
+
def traverse_gte_desc(node, key, safe: false, &block) =
|
|
736
|
+
traverse_range_desc(node, key, nil, true, false, safe: safe, &block)
|
|
696
737
|
|
|
697
738
|
# Traverses nodes with keys within the specified range in descending order.
|
|
698
739
|
#
|
|
@@ -703,24 +744,8 @@ class RBTree
|
|
|
703
744
|
# @param include_max [Boolean] whether to include the upper bound
|
|
704
745
|
# @yield [key, value] each matching key-value pair in descending order
|
|
705
746
|
# @return [void]
|
|
706
|
-
def traverse_between_desc(node, min, max, include_min, include_max, &block)
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
if (node.key <=> max) < 0
|
|
710
|
-
traverse_between_desc(node.right, min, max, include_min, include_max, &block)
|
|
711
|
-
end
|
|
712
|
-
|
|
713
|
-
greater = include_min ? (node.key <=> min) >= 0 : (node.key <=> min) > 0
|
|
714
|
-
less = include_max ? (node.key <=> max) <= 0 : (node.key <=> max) < 0
|
|
715
|
-
|
|
716
|
-
if greater && less
|
|
717
|
-
yield node.key, node.value
|
|
718
|
-
end
|
|
719
|
-
|
|
720
|
-
if (node.key <=> min) > 0
|
|
721
|
-
traverse_between_desc(node.left, min, max, include_min, include_max, &block)
|
|
722
|
-
end
|
|
723
|
-
end
|
|
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)
|
|
724
749
|
|
|
725
750
|
# Restores red-black tree properties after insertion.
|
|
726
751
|
#
|
|
@@ -1011,6 +1036,16 @@ class RBTree
|
|
|
1011
1036
|
predecessor
|
|
1012
1037
|
end
|
|
1013
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
|
+
|
|
1014
1049
|
# Finds the node with the smallest key that is larger than the given key.
|
|
1015
1050
|
#
|
|
1016
1051
|
# If the key exists in the tree, returns its successor node.
|
|
@@ -1051,6 +1086,16 @@ class RBTree
|
|
|
1051
1086
|
successor
|
|
1052
1087
|
end
|
|
1053
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
|
+
|
|
1054
1099
|
# Finds the leftmost (minimum) node in a subtree.
|
|
1055
1100
|
#
|
|
1056
1101
|
# @param node [Node] the root of the subtree
|
|
@@ -1062,6 +1107,11 @@ class RBTree
|
|
|
1062
1107
|
node
|
|
1063
1108
|
end
|
|
1064
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
|
+
|
|
1065
1115
|
# Finds the rightmost (maximum) node in a subtree.
|
|
1066
1116
|
#
|
|
1067
1117
|
# @param node [Node] the root of the subtree
|
|
@@ -1073,6 +1123,11 @@ class RBTree
|
|
|
1073
1123
|
node
|
|
1074
1124
|
end
|
|
1075
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
|
+
|
|
1076
1131
|
# Performs a left rotation on the given node.
|
|
1077
1132
|
#
|
|
1078
1133
|
# Transforms the tree structure:
|
|
@@ -1257,6 +1312,17 @@ end
|
|
|
1257
1312
|
# @author Masahito Suzuki
|
|
1258
1313
|
# @since 0.1.2
|
|
1259
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
|
+
|
|
1260
1326
|
# Retrieves a value associated with the given key.
|
|
1261
1327
|
#
|
|
1262
1328
|
# @param key [Object] the key to look up
|
|
@@ -1286,26 +1352,22 @@ class MultiRBTree < RBTree
|
|
|
1286
1352
|
# @return [Object, nil] the last value for the key, or nil if not found
|
|
1287
1353
|
def get_last(key) = get(key, last: true)
|
|
1288
1354
|
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
# @return [Object, nil] the first value for the key, or nil if not found
|
|
1295
|
-
def [](key) = get(key)
|
|
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
|
|
1296
1360
|
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
n = find_node(key)
|
|
1308
|
-
n == @nil_node || n.value.empty? ? nil : n.value
|
|
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]
|
|
1309
1371
|
end
|
|
1310
1372
|
|
|
1311
1373
|
# Inserts a value for the given key.
|
|
@@ -1433,7 +1495,7 @@ class MultiRBTree < RBTree
|
|
|
1433
1495
|
node.value.shift
|
|
1434
1496
|
@size -= 1
|
|
1435
1497
|
if node.value.empty?
|
|
1436
|
-
|
|
1498
|
+
delete_node(key)
|
|
1437
1499
|
end
|
|
1438
1500
|
[key, val]
|
|
1439
1501
|
end
|
|
@@ -1441,189 +1503,38 @@ class MultiRBTree < RBTree
|
|
|
1441
1503
|
def pop
|
|
1442
1504
|
n = rightmost(@root)
|
|
1443
1505
|
return nil if n == @nil_node
|
|
1506
|
+
key = n.key
|
|
1444
1507
|
val = n.value.last
|
|
1445
1508
|
n.value.pop
|
|
1446
1509
|
@size -= 1
|
|
1447
1510
|
if n.value.empty?
|
|
1448
|
-
|
|
1511
|
+
delete_node(key)
|
|
1449
1512
|
end
|
|
1450
|
-
[
|
|
1451
|
-
end
|
|
1452
|
-
|
|
1453
|
-
def min(last: false)
|
|
1454
|
-
return nil if @min_node == @nil_node || @min_node.value.empty?
|
|
1455
|
-
[@min_node.key, last ? @min_node.value.last : @min_node.value.first]
|
|
1456
|
-
end
|
|
1457
|
-
|
|
1458
|
-
def max(last: false)
|
|
1459
|
-
n = rightmost(@root)
|
|
1460
|
-
return nil if n == @nil_node || n.value.empty?
|
|
1461
|
-
[n.key, last ? n.value.last : n.value.first]
|
|
1462
|
-
end
|
|
1463
|
-
|
|
1464
|
-
def nearest(key, last: false)
|
|
1465
|
-
n = find_nearest_node(key)
|
|
1466
|
-
return nil if n == @nil_node || n.value.empty?
|
|
1467
|
-
[n.key, last ? n.value.last : n.value.first]
|
|
1468
|
-
end
|
|
1469
|
-
|
|
1470
|
-
def prev(key, last: false)
|
|
1471
|
-
n = find_predecessor_node(key)
|
|
1472
|
-
return nil if n == @nil_node || n.value.empty?
|
|
1473
|
-
[n.key, last ? n.value.last : n.value.first]
|
|
1513
|
+
[key, val]
|
|
1474
1514
|
end
|
|
1475
1515
|
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
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 }
|
|
1480
1528
|
end
|
|
1481
1529
|
|
|
1482
1530
|
private
|
|
1483
1531
|
|
|
1484
|
-
def
|
|
1485
|
-
|
|
1486
|
-
current = node
|
|
1487
|
-
while current != @nil_node || !stack.empty?
|
|
1488
|
-
while current != @nil_node
|
|
1489
|
-
stack << current
|
|
1490
|
-
current = current.left
|
|
1491
|
-
end
|
|
1492
|
-
current = stack.pop
|
|
1493
|
-
current.value.each { |v| yield current.key, v }
|
|
1494
|
-
current = current.right
|
|
1495
|
-
end
|
|
1532
|
+
def traverse_range_asc(...)
|
|
1533
|
+
super { |k, vals| vals.each { |v| yield k, v } }
|
|
1496
1534
|
end
|
|
1497
1535
|
|
|
1498
|
-
def
|
|
1499
|
-
|
|
1500
|
-
current = node
|
|
1501
|
-
while current != @nil_node || !stack.empty?
|
|
1502
|
-
while current != @nil_node
|
|
1503
|
-
stack << current
|
|
1504
|
-
current = current.right
|
|
1505
|
-
end
|
|
1506
|
-
current = stack.pop
|
|
1507
|
-
current.value.reverse_each { |v| yield current.key, v }
|
|
1508
|
-
current = current.left
|
|
1509
|
-
end
|
|
1510
|
-
end
|
|
1511
|
-
|
|
1512
|
-
def traverse_lt(node, key, &block)
|
|
1513
|
-
return if node == @nil_node
|
|
1514
|
-
|
|
1515
|
-
traverse_lt(node.left, key, &block)
|
|
1516
|
-
if (node.key <=> key) < 0
|
|
1517
|
-
node.value.each { |v| yield node.key, v }
|
|
1518
|
-
traverse_lt(node.right, key, &block)
|
|
1519
|
-
end
|
|
1520
|
-
end
|
|
1521
|
-
|
|
1522
|
-
def traverse_lte(node, key, &block)
|
|
1523
|
-
return if node == @nil_node
|
|
1524
|
-
|
|
1525
|
-
traverse_lte(node.left, key, &block)
|
|
1526
|
-
if (node.key <=> key) <= 0
|
|
1527
|
-
node.value.each { |v| yield node.key, v }
|
|
1528
|
-
traverse_lte(node.right, key, &block)
|
|
1529
|
-
end
|
|
1530
|
-
end
|
|
1531
|
-
|
|
1532
|
-
def traverse_gt(node, key, &block)
|
|
1533
|
-
return if node == @nil_node
|
|
1534
|
-
|
|
1535
|
-
if (node.key <=> key) > 0
|
|
1536
|
-
traverse_gt(node.left, key, &block)
|
|
1537
|
-
node.value.each { |v| yield node.key, v }
|
|
1538
|
-
end
|
|
1539
|
-
traverse_gt(node.right, key, &block)
|
|
1540
|
-
end
|
|
1541
|
-
|
|
1542
|
-
def traverse_gte(node, key, &block)
|
|
1543
|
-
return if node == @nil_node
|
|
1544
|
-
|
|
1545
|
-
if (node.key <=> key) >= 0
|
|
1546
|
-
traverse_gte(node.left, key, &block)
|
|
1547
|
-
node.value.each { |v| yield node.key, v }
|
|
1548
|
-
end
|
|
1549
|
-
traverse_gte(node.right, key, &block)
|
|
1550
|
-
end
|
|
1551
|
-
|
|
1552
|
-
def traverse_between(node, min, max, include_min, include_max, &block)
|
|
1553
|
-
return if node == @nil_node
|
|
1554
|
-
if (node.key <=> min) > 0
|
|
1555
|
-
traverse_between(node.left, min, max, include_min, include_max, &block)
|
|
1556
|
-
end
|
|
1557
|
-
|
|
1558
|
-
greater = include_min ? (node.key <=> min) >= 0 : (node.key <=> min) > 0
|
|
1559
|
-
less = include_max ? (node.key <=> max) <= 0 : (node.key <=> max) < 0
|
|
1560
|
-
|
|
1561
|
-
if greater && less
|
|
1562
|
-
node.value.each { |v| yield node.key, v }
|
|
1563
|
-
end
|
|
1564
|
-
|
|
1565
|
-
if (node.key <=> max) < 0
|
|
1566
|
-
traverse_between(node.right, min, max, include_min, include_max, &block)
|
|
1567
|
-
end
|
|
1568
|
-
end
|
|
1569
|
-
|
|
1570
|
-
def traverse_lt_desc(node, key, &block)
|
|
1571
|
-
return if node == @nil_node
|
|
1572
|
-
|
|
1573
|
-
if (node.key <=> key) < 0
|
|
1574
|
-
traverse_lt_desc(node.right, key, &block)
|
|
1575
|
-
node.value.reverse_each { |v| yield node.key, v }
|
|
1576
|
-
end
|
|
1577
|
-
traverse_lt_desc(node.left, key, &block)
|
|
1578
|
-
end
|
|
1579
|
-
|
|
1580
|
-
def traverse_lte_desc(node, key, &block)
|
|
1581
|
-
return if node == @nil_node
|
|
1582
|
-
|
|
1583
|
-
if (node.key <=> key) <= 0
|
|
1584
|
-
traverse_lte_desc(node.right, key, &block)
|
|
1585
|
-
node.value.reverse_each { |v| yield node.key, v }
|
|
1586
|
-
end
|
|
1587
|
-
traverse_lte_desc(node.left, key, &block)
|
|
1588
|
-
end
|
|
1589
|
-
|
|
1590
|
-
def traverse_gt_desc(node, key, &block)
|
|
1591
|
-
return if node == @nil_node
|
|
1592
|
-
|
|
1593
|
-
traverse_gt_desc(node.right, key, &block)
|
|
1594
|
-
if (node.key <=> key) > 0
|
|
1595
|
-
node.value.reverse_each { |v| yield node.key, v }
|
|
1596
|
-
traverse_gt_desc(node.left, key, &block)
|
|
1597
|
-
end
|
|
1598
|
-
end
|
|
1599
|
-
|
|
1600
|
-
def traverse_gte_desc(node, key, &block)
|
|
1601
|
-
return if node == @nil_node
|
|
1602
|
-
|
|
1603
|
-
traverse_gte_desc(node.right, key, &block)
|
|
1604
|
-
if (node.key <=> key) >= 0
|
|
1605
|
-
node.value.reverse_each { |v| yield node.key, v }
|
|
1606
|
-
traverse_gte_desc(node.left, key, &block)
|
|
1607
|
-
end
|
|
1608
|
-
end
|
|
1609
|
-
|
|
1610
|
-
def traverse_between_desc(node, min, max, include_min, include_max, &block)
|
|
1611
|
-
return if node == @nil_node
|
|
1612
|
-
|
|
1613
|
-
if (node.key <=> max) < 0
|
|
1614
|
-
traverse_between_desc(node.right, min, max, include_min, include_max, &block)
|
|
1615
|
-
end
|
|
1616
|
-
|
|
1617
|
-
greater = include_min ? (node.key <=> min) >= 0 : (node.key <=> min) > 0
|
|
1618
|
-
less = include_max ? (node.key <=> max) <= 0 : (node.key <=> max) < 0
|
|
1619
|
-
|
|
1620
|
-
if greater && less
|
|
1621
|
-
node.value.reverse_each { |v| yield node.key, v }
|
|
1622
|
-
end
|
|
1623
|
-
|
|
1624
|
-
if (node.key <=> min) > 0
|
|
1625
|
-
traverse_between_desc(node.left, min, max, include_min, include_max, &block)
|
|
1626
|
-
end
|
|
1536
|
+
def traverse_range_desc(...)
|
|
1537
|
+
super { |k, vals| vals.reverse_each { |v| yield k, v } }
|
|
1627
1538
|
end
|
|
1628
1539
|
end
|
|
1629
1540
|
|
|
@@ -1671,11 +1582,7 @@ class RBTree::Node
|
|
|
1671
1582
|
@parent = parent
|
|
1672
1583
|
end
|
|
1673
1584
|
|
|
1674
|
-
#
|
|
1675
|
-
# @return [
|
|
1676
|
-
def
|
|
1677
|
-
|
|
1678
|
-
# Checks if the node is black.
|
|
1679
|
-
# @return [Boolean] true if black, false otherwise
|
|
1680
|
-
def black? = @color == BLACK
|
|
1585
|
+
# Returns the key-value pair.
|
|
1586
|
+
# @return [Array(Object, Object)] the key-value pair
|
|
1587
|
+
def pair = [key, value]
|
|
1681
1588
|
end
|