rbtree-ruby 0.2.3 → 0.3.1
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 +32 -13
- data/README.md +32 -13
- data/lib/rbtree/version.rb +1 -1
- data/lib/rbtree.rb +379 -226
- 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: df8aaee3fedf309a0079082fa38c10e3748bc68873131800e13f30dee1202273
|
|
4
|
+
data.tar.gz: 5e6dd162b0ebb1b50929d9127c4ac57598c7391ecf63a7d1dca7e42107d4ca3a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c1df7b56cad01d4a0725668f415510a3e65fd6409a0271143504ec1223d64a7e395a93a1dbd43881ceb75e5a36ea9328f60e86e95cdfcde653ab075fab81cb7b
|
|
7
|
+
data.tar.gz: cecad1db1c9fba3eb4c91b20493dc849cfbf70f8d2e1fede1c09e8b22d59d925e724e26788e06627a02b620de42c655afef4a8be51d31fdeaff5fa5158a2d192
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,34 @@ 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.3.1] - 2026-01-15
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **`to_h`**: Added `to_h` method to `RBTree` and `MultiRBTree` for efficient conversion to Hash.
|
|
12
|
+
- **`merge!`**: Added `merge!` method to `RBTree` and `MultiRBTree`.
|
|
13
|
+
- `RBTree#merge!`: Supports `overwrite` option (default: `true`). Raises `ArgumentError` if merging a `MultiRBTree` (incompatible value structures).
|
|
14
|
+
- `MultiRBTree#merge!`: Always appends values from the source.
|
|
15
|
+
|
|
16
|
+
## [0.3.0] - 2026-01-15
|
|
17
|
+
|
|
18
|
+
### API Changes (Method Renaming & Deprecation)
|
|
19
|
+
> [!WARNING]
|
|
20
|
+
> The public API has been refactored to improve consistency. The following methods have been renamed.
|
|
21
|
+
> Old methods are preserved as aliases for backward compatibility but are **deprecated** and may be removed in future versions.
|
|
22
|
+
|
|
23
|
+
* `get_all` -> `values` (Returns Enumerator by default)
|
|
24
|
+
* `delete_one` -> `delete_value`
|
|
25
|
+
* `delete` (MultiRBTree) -> `delete_key`
|
|
26
|
+
* *Note: `delete` is now an alias for `delete_key` in MultiRBTree for compatibility.*
|
|
27
|
+
* `get` (MultiRBTree) -> *Behavior clarified*: Returns first value (alias for `first_value` or `value(key)`)
|
|
28
|
+
* `get_first`/`get_last` -> `first_value`/`last_value`
|
|
29
|
+
* `delete_first`/`delete_last` -> `delete_first_value`/`delete_last_value`
|
|
30
|
+
|
|
31
|
+
- **Visibility**: `insert_entry` (RBTree) and traversal helper methods (MultiRBTree) are now `private` instead of `protected`, as they are internal implementation details.
|
|
32
|
+
|
|
33
|
+
### Fixed
|
|
34
|
+
- **MultiRBTree Traversal Fix**: Fixed an issue where `MultiRBTree#each` and other traversal methods yielded `key, value` as separate arguments instead of a single `[key, value]` array. This ensures compatibility with `Enumerable` methods like `count` and consistent behavior with `RBTree` and standard `Hash`.
|
|
35
|
+
|
|
8
36
|
## [0.2.3] - 2026-01-14
|
|
9
37
|
|
|
10
38
|
### Added
|
|
@@ -163,6 +191,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
163
191
|
- ASCII diagrams for tree rotation operations
|
|
164
192
|
- MIT License (Copyright © 2026 Masahito Suzuki)
|
|
165
193
|
|
|
194
|
+
[0.3.0]: https://github.com/firelzrd/rbtree-ruby/releases/tag/v0.3.0
|
|
195
|
+
[0.2.3]: https://github.com/firelzrd/rbtree-ruby/releases/tag/v0.2.3
|
|
196
|
+
[0.2.2]: https://github.com/firelzrd/rbtree-ruby/releases/tag/v0.2.2
|
|
197
|
+
[0.2.1]: https://github.com/firelzrd/rbtree-ruby/releases/tag/v0.2.1
|
|
166
198
|
[0.2.0]: https://github.com/firelzrd/rbtree-ruby/releases/tag/v0.2.0
|
|
167
199
|
[0.1.8]: https://github.com/firelzrd/rbtree-ruby/releases/tag/v0.1.8
|
|
168
200
|
[0.1.7]: https://github.com/firelzrd/rbtree-ruby/releases/tag/v0.1.7
|
data/README.ja.md
CHANGED
|
@@ -108,11 +108,11 @@ tree.insert(2, 'two')
|
|
|
108
108
|
tree.size # => 4 (キーバリューペアの総数)
|
|
109
109
|
|
|
110
110
|
# 最初の値を取得
|
|
111
|
-
tree.
|
|
111
|
+
tree.value(1) # => "first one"
|
|
112
112
|
tree[1] # => "first one"
|
|
113
113
|
|
|
114
114
|
# キーの全ての値を取得(Enumeratorを返す)
|
|
115
|
-
tree.
|
|
115
|
+
tree.values(1).to_a # => ["first one", "second one", "third one"]
|
|
116
116
|
|
|
117
117
|
# 全キーバリューペアをイテレーション
|
|
118
118
|
tree.each { |k, v| puts "#{k}: #{v}" }
|
|
@@ -123,11 +123,11 @@ tree.each { |k, v| puts "#{k}: #{v}" }
|
|
|
123
123
|
# 2: two
|
|
124
124
|
|
|
125
125
|
# 最初の値のみ削除
|
|
126
|
-
tree.
|
|
127
|
-
tree.
|
|
126
|
+
tree.delete_value(1) # => "first one"
|
|
127
|
+
tree.value(1) # => "second one"
|
|
128
128
|
|
|
129
129
|
# キーの全ての値を削除
|
|
130
|
-
tree.
|
|
130
|
+
tree.delete_key(1) # 残りの値を全て削除
|
|
131
131
|
```
|
|
132
132
|
|
|
133
133
|
### 最近傍キー検索
|
|
@@ -174,6 +174,25 @@ tree.lt(3).first # => [1, "one"] (遅延評価、配列は作
|
|
|
174
174
|
tree.gt(0).lazy.take(2).to_a # => [[1, "one"], [2, "two"]] (最初の2件のみ計算)
|
|
175
175
|
```
|
|
176
176
|
|
|
177
|
+
### 変換と結合
|
|
178
|
+
|
|
179
|
+
標準のRubyオブジェクトへの変換や、他のコレクションとの結合も簡単です:
|
|
180
|
+
|
|
181
|
+
```ruby
|
|
182
|
+
tree = RBTree.new({1 => 'one', 2 => 'two'})
|
|
183
|
+
|
|
184
|
+
# 配列への変換(Enumerable経由)
|
|
185
|
+
tree.to_a # => [[1, "one"], [2, "two"]]
|
|
186
|
+
|
|
187
|
+
# ハッシュへの変換
|
|
188
|
+
tree.to_h # => {1 => "one", 2 => "two"}
|
|
189
|
+
|
|
190
|
+
# 他のツリー、ハッシュ、またはEnumerableの結合
|
|
191
|
+
other = {3 => 'three'}
|
|
192
|
+
tree.merge!(other)
|
|
193
|
+
tree.size # => 3
|
|
194
|
+
```
|
|
195
|
+
|
|
177
196
|
### MultiRBTree 値配列アクセス
|
|
178
197
|
|
|
179
198
|
複数の値を持つキーで、どの値にアクセスするか選択:
|
|
@@ -185,15 +204,15 @@ tree.insert(1, 'second')
|
|
|
185
204
|
tree.insert(1, 'third')
|
|
186
205
|
|
|
187
206
|
# 最初または最後の値にアクセス
|
|
188
|
-
tree.
|
|
189
|
-
tree.
|
|
190
|
-
tree.
|
|
191
|
-
tree.
|
|
207
|
+
tree.value(1) # => "first"
|
|
208
|
+
tree.value(1, last: true) # => "third"
|
|
209
|
+
tree.first_value(1) # => "first"
|
|
210
|
+
tree.last_value(1) # => "third"
|
|
192
211
|
|
|
193
212
|
# どちらの端からも削除可能
|
|
194
|
-
tree.
|
|
195
|
-
tree.
|
|
196
|
-
tree.
|
|
213
|
+
tree.delete_first_value(1) # => "first"
|
|
214
|
+
tree.delete_last_value(1) # => "third"
|
|
215
|
+
tree.value(1) # => "second"
|
|
197
216
|
|
|
198
217
|
# min/maxの:lastオプション
|
|
199
218
|
tree.insert(2, 'a')
|
|
@@ -208,7 +227,7 @@ tree.max(last: true) # => [2, "b"] (最大キーの最後の値)
|
|
|
208
227
|
|
|
209
228
|
- `insert(key, value)` - O(log n)
|
|
210
229
|
- `delete(key)` - O(log n)
|
|
211
|
-
- `
|
|
230
|
+
- `value(key)` / `[]` - **O(1)** (内部ハッシュインデックスによる超高速アクセス)
|
|
212
231
|
- `has_key?` - **O(1)** (内部ハッシュインデックスによる超高速チェック)
|
|
213
232
|
- `min` - **O(1)**
|
|
214
233
|
- `max` - O(log n)
|
data/README.md
CHANGED
|
@@ -108,11 +108,11 @@ tree.insert(2, 'two')
|
|
|
108
108
|
tree.size # => 4 (total number of key-value pairs)
|
|
109
109
|
|
|
110
110
|
# Get first value
|
|
111
|
-
tree.
|
|
111
|
+
tree.value(1) # => "first one"
|
|
112
112
|
tree[1] # => "first one"
|
|
113
113
|
|
|
114
114
|
# Get all values for a key (returns Enumerator)
|
|
115
|
-
tree.
|
|
115
|
+
tree.values(1).to_a # => ["first one", "second one", "third one"]
|
|
116
116
|
|
|
117
117
|
# Iterate over all key-value pairs
|
|
118
118
|
tree.each { |k, v| puts "#{k}: #{v}" }
|
|
@@ -123,11 +123,11 @@ tree.each { |k, v| puts "#{k}: #{v}" }
|
|
|
123
123
|
# 2: two
|
|
124
124
|
|
|
125
125
|
# Delete only first value
|
|
126
|
-
tree.
|
|
127
|
-
tree.
|
|
126
|
+
tree.delete_value(1) # => "first one"
|
|
127
|
+
tree.value(1) # => "second one"
|
|
128
128
|
|
|
129
129
|
# Delete all values for a key
|
|
130
|
-
tree.
|
|
130
|
+
tree.delete_key(1) # removes all remaining values
|
|
131
131
|
```
|
|
132
132
|
|
|
133
133
|
### Nearest Key Search
|
|
@@ -174,6 +174,25 @@ tree.lt(3).first # => [1, "one"] (lazy, no array created)
|
|
|
174
174
|
tree.gt(0).lazy.take(2).to_a # => [[1, "one"], [2, "two"]] (only computes first 2)
|
|
175
175
|
```
|
|
176
176
|
|
|
177
|
+
### Conversion and Merging
|
|
178
|
+
|
|
179
|
+
Seamlessly convert to standard Ruby objects or merge other collections:
|
|
180
|
+
|
|
181
|
+
```ruby
|
|
182
|
+
tree = RBTree.new({1 => 'one', 2 => 'two'})
|
|
183
|
+
|
|
184
|
+
# Convert to Array (via Enumerable)
|
|
185
|
+
tree.to_a # => [[1, "one"], [2, "two"]]
|
|
186
|
+
|
|
187
|
+
# Convert to Hash
|
|
188
|
+
tree.to_h # => {1 => "one", 2 => "two"}
|
|
189
|
+
|
|
190
|
+
# Merge another tree, hash, or enumerable
|
|
191
|
+
other = {3 => 'three'}
|
|
192
|
+
tree.merge!(other)
|
|
193
|
+
tree.size # => 3
|
|
194
|
+
```
|
|
195
|
+
|
|
177
196
|
### MultiRBTree Value Array Access
|
|
178
197
|
|
|
179
198
|
For keys with multiple values, choose which value to access:
|
|
@@ -185,15 +204,15 @@ tree.insert(1, 'second')
|
|
|
185
204
|
tree.insert(1, 'third')
|
|
186
205
|
|
|
187
206
|
# Access first or last value
|
|
188
|
-
tree.
|
|
189
|
-
tree.
|
|
190
|
-
tree.
|
|
191
|
-
tree.
|
|
207
|
+
tree.value(1) # => "first"
|
|
208
|
+
tree.value(1, last: true) # => "third"
|
|
209
|
+
tree.first_value(1) # => "first"
|
|
210
|
+
tree.last_value(1) # => "third"
|
|
192
211
|
|
|
193
212
|
# Delete from either end
|
|
194
|
-
tree.
|
|
195
|
-
tree.
|
|
196
|
-
tree.
|
|
213
|
+
tree.delete_first_value(1) # => "first"
|
|
214
|
+
tree.delete_last_value(1) # => "third"
|
|
215
|
+
tree.value(1) # => "second"
|
|
197
216
|
|
|
198
217
|
# min/max with :last option
|
|
199
218
|
tree.insert(2, 'a')
|
|
@@ -208,7 +227,7 @@ All major operations run in **O(log n)** time:
|
|
|
208
227
|
|
|
209
228
|
- `insert(key, value)` - O(log n)
|
|
210
229
|
- `delete(key)` - O(log n)
|
|
211
|
-
- `
|
|
230
|
+
- `value(key)` / `[]` - **O(1)** (hybrid hash index)
|
|
212
231
|
- `has_key?` - **O(1)** (hybrid hash index)
|
|
213
232
|
- `min` - **O(1)**
|
|
214
233
|
- `max` - O(log n)
|
data/lib/rbtree/version.rb
CHANGED
data/lib/rbtree.rb
CHANGED
|
@@ -56,7 +56,7 @@ class RBTree
|
|
|
56
56
|
|
|
57
57
|
# Returns the number of key-value pairs stored in the tree.
|
|
58
58
|
# @return [Integer] the number of entries in the tree
|
|
59
|
-
attr_reader :
|
|
59
|
+
attr_reader :key_count
|
|
60
60
|
|
|
61
61
|
# Creates a new RBTree from the given arguments.
|
|
62
62
|
#
|
|
@@ -100,17 +100,35 @@ class RBTree
|
|
|
100
100
|
@min_node = @nil_node
|
|
101
101
|
@hash_index = {} # Hash index for O(1) key lookup
|
|
102
102
|
@node_pool = [] # Memory pool for recycling nodes
|
|
103
|
-
@
|
|
103
|
+
@key_count = 0
|
|
104
104
|
|
|
105
105
|
if args.size > 0 || block_given?
|
|
106
106
|
insert(*args, overwrite: overwrite, &block)
|
|
107
107
|
end
|
|
108
108
|
end
|
|
109
109
|
|
|
110
|
+
# Returns a Hash containing all key-value pairs from the tree.
|
|
111
|
+
#
|
|
112
|
+
# @return [Hash] a new Hash with the tree's contents
|
|
113
|
+
def to_h = @hash_index.transform_values(&:value)
|
|
114
|
+
|
|
110
115
|
# Checks if the tree is empty.
|
|
111
116
|
#
|
|
112
117
|
# @return [Boolean] true if the tree contains no elements, false otherwise
|
|
113
|
-
def empty? = @
|
|
118
|
+
def empty? = @hash_index.empty?
|
|
119
|
+
|
|
120
|
+
# Returns the number of key-value pairs stored in the tree.
|
|
121
|
+
# @return [Integer] the number of entries in the tree
|
|
122
|
+
def size = @key_count
|
|
123
|
+
alias :value_count :size
|
|
124
|
+
|
|
125
|
+
# Returns the minimum key without removing it.
|
|
126
|
+
#
|
|
127
|
+
# @return [Object, nil] the minimum key, or nil if tree is empty
|
|
128
|
+
# @example
|
|
129
|
+
# tree = RBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
|
|
130
|
+
# tree.min_key # => 1
|
|
131
|
+
def min_key = min_node&.key
|
|
114
132
|
|
|
115
133
|
# Returns the minimum key-value pair without removing it.
|
|
116
134
|
#
|
|
@@ -118,7 +136,15 @@ class RBTree
|
|
|
118
136
|
# @example
|
|
119
137
|
# tree = RBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
|
|
120
138
|
# tree.min # => [1, "one"]
|
|
121
|
-
def min =
|
|
139
|
+
def min = min_node&.pair
|
|
140
|
+
|
|
141
|
+
# Returns the maximum key without removing it.
|
|
142
|
+
#
|
|
143
|
+
# @return [Object, nil] the maximum key, or nil if tree is empty
|
|
144
|
+
# @example
|
|
145
|
+
# tree = RBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
|
|
146
|
+
# tree.max_key # => 3
|
|
147
|
+
def max_key = max_node&.key
|
|
122
148
|
|
|
123
149
|
# Returns the maximum key-value pair without removing it.
|
|
124
150
|
#
|
|
@@ -126,7 +152,23 @@ class RBTree
|
|
|
126
152
|
# @example
|
|
127
153
|
# tree = RBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
|
|
128
154
|
# tree.max # => [3, "three"]
|
|
129
|
-
def max =
|
|
155
|
+
def max = max_node&.pair
|
|
156
|
+
|
|
157
|
+
# Returns the first key-value pair without removing it.
|
|
158
|
+
#
|
|
159
|
+
# @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
|
|
160
|
+
# @example
|
|
161
|
+
# tree = RBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
|
|
162
|
+
# tree.first # => [1, "one"]
|
|
163
|
+
def first = min
|
|
164
|
+
|
|
165
|
+
# Returns the last key-value pair without removing it.
|
|
166
|
+
#
|
|
167
|
+
# @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
|
|
168
|
+
# @example
|
|
169
|
+
# tree = RBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
|
|
170
|
+
# tree.last # => [3, "three"]
|
|
171
|
+
def last = max
|
|
130
172
|
|
|
131
173
|
# Checks if the tree contains the given key.
|
|
132
174
|
#
|
|
@@ -134,11 +176,10 @@ class RBTree
|
|
|
134
176
|
# @return [Boolean] true if the key exists in the tree, false otherwise
|
|
135
177
|
# @example
|
|
136
178
|
# tree = RBTree.new({1 => 'one', 2 => 'two'})
|
|
137
|
-
# tree.
|
|
138
|
-
# tree.
|
|
139
|
-
def has_key?(key)
|
|
140
|
-
|
|
141
|
-
end
|
|
179
|
+
# tree.key?(1) # => true
|
|
180
|
+
# tree.key?(3) # => false
|
|
181
|
+
def has_key?(key) = @hash_index.key?(key)
|
|
182
|
+
alias :key? :has_key?
|
|
142
183
|
|
|
143
184
|
# Retrieves the value associated with the given key.
|
|
144
185
|
#
|
|
@@ -149,10 +190,22 @@ class RBTree
|
|
|
149
190
|
# tree.get(1) # => "one"
|
|
150
191
|
# tree[2] # => "two"
|
|
151
192
|
# tree[3] # => nil
|
|
152
|
-
def
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
193
|
+
def value(key) = @hash_index[key]&.value
|
|
194
|
+
alias :get :value
|
|
195
|
+
alias :[] :value
|
|
196
|
+
|
|
197
|
+
# Returns the key with the key closest to the given key.
|
|
198
|
+
#
|
|
199
|
+
# This method requires keys to be numeric or support subtraction and abs methods.
|
|
200
|
+
#
|
|
201
|
+
# @param key [Numeric] the target key
|
|
202
|
+
# @return [Object, nil] the key, or nil if tree is empty
|
|
203
|
+
# @example
|
|
204
|
+
# tree = RBTree.new({1 => 'one', 5 => 'five', 10 => 'ten'})
|
|
205
|
+
# tree.nearest_key(4) # => 5
|
|
206
|
+
# tree.nearest_key(7) # => 5
|
|
207
|
+
# tree.nearest_key(8) # => 10
|
|
208
|
+
def nearest_key(key) = ((n = find_nearest_node(key)) == @nil_node)? nil : n.key
|
|
156
209
|
|
|
157
210
|
# Returns the key-value pair with the key closest to the given key.
|
|
158
211
|
#
|
|
@@ -166,11 +219,21 @@ class RBTree
|
|
|
166
219
|
# tree.nearest(4) # => [5, "five"]
|
|
167
220
|
# tree.nearest(7) # => [5, "five"]
|
|
168
221
|
# tree.nearest(8) # => [10, "ten"]
|
|
169
|
-
def nearest(key)
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
222
|
+
def nearest(key) = ((n = find_nearest_node(key)) == @nil_node)? nil : n.pair
|
|
223
|
+
|
|
224
|
+
# Returns the key with the largest key that is smaller than the given key.
|
|
225
|
+
#
|
|
226
|
+
# If the key exists in the tree, returns the predecessor (previous element).
|
|
227
|
+
# If the key does not exist, returns the largest key with key < given key.
|
|
228
|
+
#
|
|
229
|
+
# @param key [Object] the reference key
|
|
230
|
+
# @return [Object, nil] the key, or nil if no predecessor exists
|
|
231
|
+
# @example
|
|
232
|
+
# tree = RBTree.new({1 => 'one', 3 => 'three', 5 => 'five', 7 => 'seven'})
|
|
233
|
+
# tree.prev_key(5) # => 3
|
|
234
|
+
# tree.prev_key(4) # => 3 (4 does not exist)
|
|
235
|
+
# tree.prev_key(1) # => nil (no predecessor)
|
|
236
|
+
def prev_key(key) = ((n = find_predecessor_node(key)) == @nil_node)? nil : n.key
|
|
174
237
|
|
|
175
238
|
# Returns the key-value pair with the largest key that is smaller than the given key.
|
|
176
239
|
#
|
|
@@ -184,10 +247,21 @@ class RBTree
|
|
|
184
247
|
# tree.prev(5) # => [3, "three"]
|
|
185
248
|
# tree.prev(4) # => [3, "three"] (4 does not exist)
|
|
186
249
|
# tree.prev(1) # => nil (no predecessor)
|
|
187
|
-
def prev(key)
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
250
|
+
def prev(key) = ((n = find_predecessor_node(key)) == @nil_node)? nil : n.pair
|
|
251
|
+
|
|
252
|
+
# Returns the key with the smallest key that is larger than the given key.
|
|
253
|
+
#
|
|
254
|
+
# If the key exists in the tree, returns the successor (next element).
|
|
255
|
+
# If the key does not exist, returns the smallest key with key > given key.
|
|
256
|
+
#
|
|
257
|
+
# @param key [Object] the reference key
|
|
258
|
+
# @return [Object, nil] the key, or nil if no successor exists
|
|
259
|
+
# @example
|
|
260
|
+
# tree = RBTree.new({1 => 'one', 3 => 'three', 5 => 'five', 7 => 'seven'})
|
|
261
|
+
# tree.succ_key(5) # => 7
|
|
262
|
+
# tree.succ_key(4) # => 5 (4 does not exist)
|
|
263
|
+
# tree.succ_key(1) # => 3 (1 does not exist)
|
|
264
|
+
def succ_key(key) = ((n = find_successor_node(key)) == @nil_node)? nil : n.key
|
|
191
265
|
|
|
192
266
|
# Returns the key-value pair with the smallest key that is larger than the given key.
|
|
193
267
|
#
|
|
@@ -201,10 +275,7 @@ class RBTree
|
|
|
201
275
|
# tree.succ(5) # => [7, "seven"]
|
|
202
276
|
# tree.succ(4) # => [5, "five"] (4 does not exist)
|
|
203
277
|
# tree.succ(7) # => nil (no successor)
|
|
204
|
-
def succ(key)
|
|
205
|
-
n = find_successor_node(key)
|
|
206
|
-
n == @nil_node ? nil : n.pair
|
|
207
|
-
end
|
|
278
|
+
def succ(key) = ((n = find_successor_node(key)) == @nil_node)? nil : n.pair
|
|
208
279
|
|
|
209
280
|
# Inserts one or more key-value pairs into the tree.
|
|
210
281
|
#
|
|
@@ -268,7 +339,20 @@ class RBTree
|
|
|
268
339
|
end
|
|
269
340
|
end
|
|
270
341
|
end
|
|
271
|
-
|
|
342
|
+
alias :[]= :insert
|
|
343
|
+
|
|
344
|
+
# Merges the contents of another tree, hash, or enumerable into this tree.
|
|
345
|
+
#
|
|
346
|
+
# @param other [RBTree, Hash, Enumerable] the source to merge from
|
|
347
|
+
# @param overwrite [Boolean] whether to overwrite existing keys (default: true)
|
|
348
|
+
# @return [RBTree] self
|
|
349
|
+
def merge!(other, overwrite: true)
|
|
350
|
+
if defined?(MultiRBTree) && other.is_a?(MultiRBTree)
|
|
351
|
+
raise ArgumentError, "Cannot merge MultiRBTree into RBTree"
|
|
352
|
+
end
|
|
353
|
+
insert(other, overwrite: overwrite)
|
|
354
|
+
self
|
|
355
|
+
end
|
|
272
356
|
|
|
273
357
|
# Deletes the key-value pair with the specified key.
|
|
274
358
|
#
|
|
@@ -278,12 +362,12 @@ class RBTree
|
|
|
278
362
|
# tree = RBTree.new({1 => 'one', 2 => 'two'})
|
|
279
363
|
# tree.delete(1) # => "one"
|
|
280
364
|
# tree.delete(3) # => nil
|
|
281
|
-
def
|
|
282
|
-
value =
|
|
283
|
-
|
|
284
|
-
@size -= 1
|
|
365
|
+
def delete_key(key)
|
|
366
|
+
return nil unless (value = (z = @hash_index[key])&.value)
|
|
367
|
+
delete_indexed_node(key)
|
|
285
368
|
value
|
|
286
369
|
end
|
|
370
|
+
alias :delete :delete_key
|
|
287
371
|
|
|
288
372
|
# Removes and returns the minimum key-value pair.
|
|
289
373
|
#
|
|
@@ -293,10 +377,10 @@ class RBTree
|
|
|
293
377
|
# tree.shift # => [1, "one"]
|
|
294
378
|
# tree.shift # => [2, "two"]
|
|
295
379
|
def shift
|
|
296
|
-
return nil
|
|
297
|
-
|
|
298
|
-
delete(
|
|
299
|
-
|
|
380
|
+
return nil unless (n = @min_node) != @nil_node
|
|
381
|
+
pair = n.pair
|
|
382
|
+
delete(n.key)
|
|
383
|
+
pair
|
|
300
384
|
end
|
|
301
385
|
|
|
302
386
|
# Removes and returns the maximum key-value pair.
|
|
@@ -307,21 +391,46 @@ class RBTree
|
|
|
307
391
|
# tree.pop # => [3, "three"]
|
|
308
392
|
# tree.pop # => [2, "two"]
|
|
309
393
|
def pop
|
|
310
|
-
n = rightmost(@root)
|
|
311
|
-
|
|
312
|
-
result = n.pair
|
|
394
|
+
return nil unless (n = rightmost(@root)) != @nil_node
|
|
395
|
+
pair = n.pair
|
|
313
396
|
delete(n.key)
|
|
314
|
-
|
|
397
|
+
pair
|
|
315
398
|
end
|
|
316
399
|
|
|
317
400
|
# Removes all key-value pairs from the tree.
|
|
318
401
|
#
|
|
319
402
|
# @return [RBTree] self
|
|
320
403
|
def clear
|
|
321
|
-
@root = @nil_node
|
|
322
|
-
@min_node = @nil_node
|
|
404
|
+
@root = @min_node = @nil_node
|
|
323
405
|
@hash_index.clear
|
|
324
|
-
@
|
|
406
|
+
@key_count = 0
|
|
407
|
+
self
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
# Iterates over all keys in ascending (or descending) order.
|
|
411
|
+
#
|
|
412
|
+
# @param reverse [Boolean] if true, iterate in descending order (default: false)
|
|
413
|
+
# @param safe [Boolean] if true, safe for modifications during iteration (default: false)
|
|
414
|
+
# @yield [key] each key in the tree
|
|
415
|
+
# @return [Enumerator, RBTree] an Enumerator if no block is given, self otherwise
|
|
416
|
+
# @example
|
|
417
|
+
# tree = RBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
|
|
418
|
+
# tree.keys { |k| puts k }
|
|
419
|
+
# # Output:
|
|
420
|
+
# # 1
|
|
421
|
+
# # 2
|
|
422
|
+
# # 3
|
|
423
|
+
#
|
|
424
|
+
# # Reverse iteration
|
|
425
|
+
# tree.keys(reverse: true) { |k| ... }
|
|
426
|
+
#
|
|
427
|
+
# # Safe iteration for modifications
|
|
428
|
+
# tree.keys(safe: true) do |k|
|
|
429
|
+
# tree.delete(k) if k.even?
|
|
430
|
+
# end
|
|
431
|
+
def keys(reverse: false, safe: false, &block)
|
|
432
|
+
return enum_for(:keys, reverse: reverse, safe: safe) { @key_count } unless block_given?
|
|
433
|
+
each(reverse: reverse, safe: safe) { |key, _| yield key }
|
|
325
434
|
self
|
|
326
435
|
end
|
|
327
436
|
|
|
@@ -347,7 +456,7 @@ class RBTree
|
|
|
347
456
|
# tree.delete(k) if k.even?
|
|
348
457
|
# end
|
|
349
458
|
def each(reverse: false, safe: false, &block)
|
|
350
|
-
return enum_for(:each, reverse: reverse, safe: safe) unless block_given?
|
|
459
|
+
return enum_for(:each, reverse: reverse, safe: safe) { size } unless block_given?
|
|
351
460
|
if reverse
|
|
352
461
|
traverse_all_desc(@root, safe: safe, &block)
|
|
353
462
|
else
|
|
@@ -375,7 +484,10 @@ class RBTree
|
|
|
375
484
|
# @yield [key, value] each key-value pair in the tree
|
|
376
485
|
# @return [Enumerator, RBTree] an Enumerator if no block is given, self otherwise
|
|
377
486
|
# @see #each
|
|
378
|
-
def reverse_each(safe: false, &block)
|
|
487
|
+
def reverse_each(safe: false, &block)
|
|
488
|
+
return enum_for(:reverse_each, safe: safe) { size } unless block_given?
|
|
489
|
+
each(reverse: true, safe: safe, &block)
|
|
490
|
+
end
|
|
379
491
|
|
|
380
492
|
# Retrieves all key-value pairs with keys less than the specified key.
|
|
381
493
|
#
|
|
@@ -492,13 +604,9 @@ class RBTree
|
|
|
492
604
|
#
|
|
493
605
|
# @return [String] a human-readable representation of the tree
|
|
494
606
|
def inspect
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
"#<#{self.class}:0x#{object_id.to_s(16)} size=#{@size} {#{content}#{suffix}}>"
|
|
499
|
-
else
|
|
500
|
-
super
|
|
501
|
-
end
|
|
607
|
+
content = take(5).map { |k, v| "#{k.inspect}=>#{v.inspect}" }.join(", ")
|
|
608
|
+
suffix = size > 5 ? ", ..." : ""
|
|
609
|
+
"#<#{self.class}:0x#{object_id.to_s(16)} size=#{size} {#{content}#{suffix}}>"
|
|
502
610
|
end
|
|
503
611
|
|
|
504
612
|
# Validates the red-black tree properties.
|
|
@@ -517,8 +625,12 @@ class RBTree
|
|
|
517
625
|
true
|
|
518
626
|
end
|
|
519
627
|
|
|
520
|
-
# @!visibility
|
|
521
|
-
|
|
628
|
+
# @!visibility private
|
|
629
|
+
private
|
|
630
|
+
|
|
631
|
+
def min_node = ((n = @min_node) == @nil_node) ? nil : n
|
|
632
|
+
|
|
633
|
+
def max_node = ((n = rightmost(@root)) == @nil_node) ? nil : n
|
|
522
634
|
|
|
523
635
|
# Inserts a single key-value pair.
|
|
524
636
|
#
|
|
@@ -560,7 +672,6 @@ class RBTree
|
|
|
560
672
|
z.right = @nil_node
|
|
561
673
|
z.color = Node::RED
|
|
562
674
|
insert_fixup(z)
|
|
563
|
-
@size += 1
|
|
564
675
|
|
|
565
676
|
if @min_node == @nil_node || (key <=> @min_node.key) < 0
|
|
566
677
|
@min_node = z
|
|
@@ -846,11 +957,7 @@ class RBTree
|
|
|
846
957
|
#
|
|
847
958
|
# @param key [Object] the key to delete
|
|
848
959
|
# @return [Object, nil] the value of the deleted node, or nil if not found
|
|
849
|
-
def
|
|
850
|
-
z = @hash_index.delete(key) # O(1) lookup and remove from index
|
|
851
|
-
return nil unless z
|
|
852
|
-
remove_node(z)
|
|
853
|
-
end
|
|
960
|
+
def delete_indexed_node(key) = (z = @hash_index.delete(key)) && delete_node(z)
|
|
854
961
|
|
|
855
962
|
# Removes a node from the tree and restores red-black properties.
|
|
856
963
|
#
|
|
@@ -861,7 +968,7 @@ class RBTree
|
|
|
861
968
|
#
|
|
862
969
|
# @param z [Node] the node to remove
|
|
863
970
|
# @return [Object] the value of the removed node
|
|
864
|
-
def
|
|
971
|
+
def delete_node(z)
|
|
865
972
|
next_min_node = nil
|
|
866
973
|
if z == @min_node
|
|
867
974
|
if z.right != @nil_node
|
|
@@ -986,25 +1093,6 @@ class RBTree
|
|
|
986
1093
|
v.parent = u.parent
|
|
987
1094
|
end
|
|
988
1095
|
|
|
989
|
-
# Searches for a node with the given key.
|
|
990
|
-
#
|
|
991
|
-
# @param key [Object] the key to search for
|
|
992
|
-
# @return [Node] the found node, or @nil_node if not found
|
|
993
|
-
def find_node(key)
|
|
994
|
-
current = @root
|
|
995
|
-
while current != @nil_node
|
|
996
|
-
cmp = key <=> current.key
|
|
997
|
-
if cmp == 0
|
|
998
|
-
return current
|
|
999
|
-
elsif cmp < 0
|
|
1000
|
-
current = current.left
|
|
1001
|
-
else
|
|
1002
|
-
current = current.right
|
|
1003
|
-
end
|
|
1004
|
-
end
|
|
1005
|
-
@nil_node
|
|
1006
|
-
end
|
|
1007
|
-
|
|
1008
1096
|
# Finds the node with the closest key to the given key.
|
|
1009
1097
|
#
|
|
1010
1098
|
# Uses numeric distance (absolute difference) to determine proximity.
|
|
@@ -1159,7 +1247,7 @@ class RBTree
|
|
|
1159
1247
|
# Returns the minimum key-value pair.
|
|
1160
1248
|
#
|
|
1161
1249
|
# @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
|
|
1162
|
-
def find_min = @min_node
|
|
1250
|
+
def find_min = ((n = @min_node) != @nil_node) && n.pair
|
|
1163
1251
|
|
|
1164
1252
|
# Finds the rightmost (maximum) node in a subtree.
|
|
1165
1253
|
#
|
|
@@ -1175,7 +1263,7 @@ class RBTree
|
|
|
1175
1263
|
# Returns the maximum key-value pair.
|
|
1176
1264
|
#
|
|
1177
1265
|
# @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
|
|
1178
|
-
def find_max = (n = rightmost(@root))
|
|
1266
|
+
def find_max = ((n = rightmost(@root)) != @nil_node) && n.pair
|
|
1179
1267
|
|
|
1180
1268
|
# Performs a left rotation on the given node.
|
|
1181
1269
|
#
|
|
@@ -1238,7 +1326,8 @@ class RBTree
|
|
|
1238
1326
|
# Allocates a new node or recycles one from the pool.
|
|
1239
1327
|
# @return [Node]
|
|
1240
1328
|
def allocate_node(key, value, color, left, right, parent)
|
|
1241
|
-
|
|
1329
|
+
node = @node_pool.pop
|
|
1330
|
+
if node
|
|
1242
1331
|
node.key = key
|
|
1243
1332
|
node.value = value
|
|
1244
1333
|
node.color = color
|
|
@@ -1247,8 +1336,10 @@ class RBTree
|
|
|
1247
1336
|
node.parent = parent
|
|
1248
1337
|
node
|
|
1249
1338
|
else
|
|
1250
|
-
Node.new(key, value, color, left, right, parent)
|
|
1339
|
+
node = Node.new(key, value, color, left, right, parent)
|
|
1251
1340
|
end
|
|
1341
|
+
@key_count += 1
|
|
1342
|
+
node
|
|
1252
1343
|
end
|
|
1253
1344
|
|
|
1254
1345
|
# Releases a node back to the pool.
|
|
@@ -1259,6 +1350,7 @@ class RBTree
|
|
|
1259
1350
|
node.parent = nil
|
|
1260
1351
|
node.value = nil # Help GC
|
|
1261
1352
|
@node_pool << node
|
|
1353
|
+
@key_count -= 1
|
|
1262
1354
|
end
|
|
1263
1355
|
|
|
1264
1356
|
# Recursively checks black height consistency.
|
|
@@ -1305,7 +1397,7 @@ end
|
|
|
1305
1397
|
# == Features
|
|
1306
1398
|
#
|
|
1307
1399
|
# * Multiple values per key using arrays
|
|
1308
|
-
# * Separate methods for single deletion (`
|
|
1400
|
+
# * Separate methods for single deletion (`delete_value`) vs. all deletions (`delete_key`)
|
|
1309
1401
|
# * Values for each key maintain insertion order
|
|
1310
1402
|
# * Configurable access to first or last value via `:last` option
|
|
1311
1403
|
#
|
|
@@ -1314,10 +1406,10 @@ end
|
|
|
1314
1406
|
# For each key, values are stored in insertion order. Methods that access
|
|
1315
1407
|
# a single value support a `:last` option to choose which end of the array:
|
|
1316
1408
|
#
|
|
1317
|
-
# * +get(key)+, +
|
|
1318
|
-
# * +get(key, last: true)+, +
|
|
1319
|
-
# * +
|
|
1320
|
-
# * +
|
|
1409
|
+
# * +get(key)+, +first_value(key)+ - returns first value (oldest)
|
|
1410
|
+
# * +get(key, last: true)+, +last_value(key)+ - returns last value (newest)
|
|
1411
|
+
# * +delete_value(key)+, +delete_first_value(key)+ - removes first value
|
|
1412
|
+
# * +delete_value(key, last: true)+, +delete_last_value(key)+ - removes last value
|
|
1321
1413
|
# * +prev(key)+, +succ(key)+ - returns first value of adjacent key
|
|
1322
1414
|
# * +prev(key, last: true)+, +succ(key, last: true)+ - returns last value
|
|
1323
1415
|
#
|
|
@@ -1351,9 +1443,9 @@ end
|
|
|
1351
1443
|
# tree.size # => 3 (total key-value pairs)
|
|
1352
1444
|
# tree.get(1) # => "first one" (first value)
|
|
1353
1445
|
# tree.get(1, last: true) # => "second one" (last value)
|
|
1354
|
-
# tree.
|
|
1446
|
+
# tree.values(1) # => ["first one", "second one"] (all values)
|
|
1355
1447
|
#
|
|
1356
|
-
# tree.
|
|
1448
|
+
# tree.delete_value(1) # removes only "first one"
|
|
1357
1449
|
# tree.get(1) # => "second one"
|
|
1358
1450
|
#
|
|
1359
1451
|
# tree.delete(1) # removes all remaining values for key 1
|
|
@@ -1361,16 +1453,46 @@ end
|
|
|
1361
1453
|
# @author Masahito Suzuki
|
|
1362
1454
|
# @since 0.1.2
|
|
1363
1455
|
class MultiRBTree < RBTree
|
|
1364
|
-
def
|
|
1365
|
-
|
|
1366
|
-
|
|
1456
|
+
def initialize(*args, **kwargs)
|
|
1457
|
+
@value_count = 0
|
|
1458
|
+
super
|
|
1367
1459
|
end
|
|
1368
1460
|
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1461
|
+
# Returns the number of values stored in the tree.
|
|
1462
|
+
# @return [Integer] the number of values in the tree
|
|
1463
|
+
def size = @value_count
|
|
1464
|
+
|
|
1465
|
+
# Returns the minimum key-value pair without removing it.
|
|
1466
|
+
#
|
|
1467
|
+
# @param last [Boolean] whether to return the last value (default: false)
|
|
1468
|
+
# @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
|
|
1469
|
+
# @example
|
|
1470
|
+
# tree = MultiRBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
|
|
1471
|
+
# tree.min # => [1, "one"]
|
|
1472
|
+
def min(last: false) = (n = min_node) && [n.key, n.value.send(last ? :last : :first)]
|
|
1473
|
+
|
|
1474
|
+
# Returns the maximum key-value pair without removing it.
|
|
1475
|
+
#
|
|
1476
|
+
# @param last [Boolean] whether to return the last value (default: false)
|
|
1477
|
+
# @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
|
|
1478
|
+
# @example
|
|
1479
|
+
# tree = MultiRBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
|
|
1480
|
+
# tree.max # => [3, "three"]
|
|
1481
|
+
def max(last: false) = (n = max_node) && [n.key, n.value.send(last ? :last : :first)]
|
|
1482
|
+
|
|
1483
|
+
# Returns the last key-value pair without removing it.
|
|
1484
|
+
#
|
|
1485
|
+
# @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
|
|
1486
|
+
# @example
|
|
1487
|
+
# tree = MultiRBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
|
|
1488
|
+
# tree.last # => [3, "three"]
|
|
1489
|
+
def last = max(last: true)
|
|
1490
|
+
|
|
1491
|
+
# Returns the number of values for a given key or the total number of key-value pairs if no key is given.
|
|
1492
|
+
#
|
|
1493
|
+
# @param key [Object, nil] the key to look up, or nil for total count
|
|
1494
|
+
# @return [Integer] the number of values for the key, or total count if no key is given
|
|
1495
|
+
def value_count(key = nil) = !key ? size : (@hash_index[key]&.value&.size || 0)
|
|
1374
1496
|
|
|
1375
1497
|
# Retrieves a value associated with the given key.
|
|
1376
1498
|
#
|
|
@@ -1383,97 +1505,76 @@ class MultiRBTree < RBTree
|
|
|
1383
1505
|
# tree.insert(1, 'second')
|
|
1384
1506
|
# tree.get(1) # => "first"
|
|
1385
1507
|
# tree.get(1, last: true) # => "second"
|
|
1386
|
-
def
|
|
1387
|
-
n = find_node(key)
|
|
1388
|
-
return nil if n == @nil_node || n.value.empty?
|
|
1389
|
-
last ? n.value.last : n.value.first
|
|
1390
|
-
end
|
|
1508
|
+
def value(key, last: false) = @hash_index[key]&.value&.send(last ? :last : :first)
|
|
1391
1509
|
|
|
1392
1510
|
# Retrieves the first value associated with the given key.
|
|
1393
1511
|
#
|
|
1394
1512
|
# @param key [Object] the key to look up
|
|
1395
1513
|
# @return [Object, nil] the first value for the key, or nil if not found
|
|
1396
|
-
def
|
|
1514
|
+
def first_value(key) = value(key)
|
|
1515
|
+
alias :get_first :first_value
|
|
1397
1516
|
|
|
1398
1517
|
# Retrieves the last value associated with the given key.
|
|
1399
1518
|
#
|
|
1400
1519
|
# @param key [Object] the key to look up
|
|
1401
1520
|
# @return [Object, nil] the last value for the key, or nil if not found
|
|
1402
|
-
def
|
|
1521
|
+
def last_value(key) = value(key, last: true)
|
|
1522
|
+
alias :get_last :last_value
|
|
1403
1523
|
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1524
|
+
# Retrieves all values associated with the given key.
|
|
1525
|
+
#
|
|
1526
|
+
# @param key [Object] the key to look up
|
|
1527
|
+
# @return [Array, nil] an Array containing all values, or nil if not found
|
|
1528
|
+
# @example
|
|
1529
|
+
# tree = MultiRBTree.new
|
|
1530
|
+
# tree.insert(1, 'first')
|
|
1531
|
+
# tree.insert(1, 'second')
|
|
1532
|
+
# tree.values(1).to_a # => ["first", "second"]
|
|
1533
|
+
def values(key, reverse: false)
|
|
1534
|
+
return enum_for(:values, key) { value_count(key) } unless block_given?
|
|
1535
|
+
@hash_index[key]&.value&.send(reverse ? :reverse_each : :each) { |v| yield v }
|
|
1408
1536
|
end
|
|
1537
|
+
alias :get_all :values
|
|
1409
1538
|
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
[pair[0], last ? pair[1].last : pair[1].first]
|
|
1420
|
-
end
|
|
1539
|
+
# Returns the nearest key-value pair without removing it.
|
|
1540
|
+
#
|
|
1541
|
+
# @param key [Object] the target key
|
|
1542
|
+
# @param last [Boolean] whether to return the last value (default: false)
|
|
1543
|
+
# @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
|
|
1544
|
+
# @example
|
|
1545
|
+
# tree = MultiRBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
|
|
1546
|
+
# tree.nearest(4) # => [5, "five"]
|
|
1547
|
+
def nearest(key, last: false) = (pair = super(key)) && [pair[0], pair[1].send(last ? :last : :first)]
|
|
1421
1548
|
|
|
1422
|
-
#
|
|
1549
|
+
# Returns the previous key-value pair without removing it.
|
|
1423
1550
|
#
|
|
1424
|
-
#
|
|
1425
|
-
#
|
|
1551
|
+
# @param key [Object] the target key
|
|
1552
|
+
# @param last [Boolean] whether to return the last value (default: false)
|
|
1553
|
+
# @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
|
|
1554
|
+
# @example
|
|
1555
|
+
# tree = MultiRBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
|
|
1556
|
+
# tree.prev(4) # => [5, "five"]
|
|
1557
|
+
def prev(key, last: false) = (pair = super(key)) && [pair[0], pair[1].send(last ? :last : :first)]
|
|
1558
|
+
|
|
1559
|
+
# Returns the next key-value pair without removing it.
|
|
1426
1560
|
#
|
|
1427
|
-
# @param key [Object] the key
|
|
1428
|
-
# @param
|
|
1429
|
-
# @
|
|
1430
|
-
# @return [Boolean] always returns true
|
|
1561
|
+
# @param key [Object] the target key
|
|
1562
|
+
# @param last [Boolean] whether to return the last value (default: false)
|
|
1563
|
+
# @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
|
|
1431
1564
|
# @example
|
|
1432
|
-
# tree = MultiRBTree.new
|
|
1433
|
-
# tree.
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
cmp = key <=> x.key
|
|
1446
|
-
if cmp == 0
|
|
1447
|
-
x.value << value
|
|
1448
|
-
@size += 1
|
|
1449
|
-
return true
|
|
1450
|
-
elsif cmp < 0
|
|
1451
|
-
x = x.left
|
|
1452
|
-
else
|
|
1453
|
-
x = x.right
|
|
1454
|
-
end
|
|
1455
|
-
end
|
|
1456
|
-
z = allocate_node(key, [value], Node::RED, @nil_node, @nil_node, @nil_node)
|
|
1457
|
-
z.parent = y
|
|
1458
|
-
if y == @nil_node
|
|
1459
|
-
@root = z
|
|
1460
|
-
elsif (key <=> y.key) < 0
|
|
1461
|
-
y.left = z
|
|
1462
|
-
else
|
|
1463
|
-
y.right = z
|
|
1464
|
-
end
|
|
1465
|
-
z.left = @nil_node
|
|
1466
|
-
z.right = @nil_node
|
|
1467
|
-
z.color = Node::RED
|
|
1468
|
-
insert_fixup(z)
|
|
1469
|
-
@size += 1
|
|
1470
|
-
|
|
1471
|
-
if @min_node == @nil_node || (key <=> @min_node.key) < 0
|
|
1472
|
-
@min_node = z
|
|
1473
|
-
end
|
|
1474
|
-
|
|
1475
|
-
@hash_index[key] = z # Add to hash index
|
|
1476
|
-
true
|
|
1565
|
+
# tree = MultiRBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
|
|
1566
|
+
# tree.succ(4) # => [5, "five"]
|
|
1567
|
+
def succ(key, last: false) = (pair = super(key)) && [pair[0], pair[1].send(last ? :last : :first)]
|
|
1568
|
+
|
|
1569
|
+
# Merges the contents of another tree, hash, or enumerable into this tree.
|
|
1570
|
+
#
|
|
1571
|
+
# Appends values from the other source to the existing values for each key.
|
|
1572
|
+
#
|
|
1573
|
+
# @param other [RBTree, Hash, Enumerable] the source to merge from
|
|
1574
|
+
# @return [MultiRBTree] self
|
|
1575
|
+
def merge!(other)
|
|
1576
|
+
insert(other)
|
|
1577
|
+
self
|
|
1477
1578
|
end
|
|
1478
1579
|
|
|
1479
1580
|
# Deletes a single value for the specified key.
|
|
@@ -1488,32 +1589,30 @@ class MultiRBTree < RBTree
|
|
|
1488
1589
|
# tree = MultiRBTree.new
|
|
1489
1590
|
# tree.insert(1, 'first')
|
|
1490
1591
|
# tree.insert(1, 'second')
|
|
1491
|
-
# tree.
|
|
1492
|
-
# tree.
|
|
1493
|
-
def
|
|
1494
|
-
z = @hash_index[key]
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
@size -= 1
|
|
1499
|
-
if z.value.empty?
|
|
1500
|
-
@hash_index.delete(key) # Remove from index when node removed
|
|
1501
|
-
remove_node(z)
|
|
1502
|
-
end
|
|
1592
|
+
# tree.delete_value(1) # => "first"
|
|
1593
|
+
# tree.delete_value(1, last: true) # => "second" (if more values existed)
|
|
1594
|
+
def delete_value(key, last: false)
|
|
1595
|
+
(z = @hash_index[key]) or return nil
|
|
1596
|
+
value = z.value.send(last ? :pop : :shift)
|
|
1597
|
+
z.value.empty? && delete_indexed_node(key)
|
|
1598
|
+
@value_count -= 1
|
|
1503
1599
|
value
|
|
1504
1600
|
end
|
|
1601
|
+
alias :delete_one :delete_value
|
|
1505
1602
|
|
|
1506
1603
|
# Deletes the first value for the specified key.
|
|
1507
1604
|
#
|
|
1508
1605
|
# @param key [Object] the key to delete from
|
|
1509
1606
|
# @return [Object, nil] the deleted value, or nil if key not found
|
|
1510
|
-
def
|
|
1607
|
+
def delete_first_value(key) = delete_value(key)
|
|
1608
|
+
alias :delete_first :delete_first_value
|
|
1511
1609
|
|
|
1512
1610
|
# Deletes the last value for the specified key.
|
|
1513
1611
|
#
|
|
1514
1612
|
# @param key [Object] the key to delete from
|
|
1515
1613
|
# @return [Object, nil] the deleted value, or nil if key not found
|
|
1516
|
-
def
|
|
1614
|
+
def delete_last_value(key) = delete_value(key, last: true)
|
|
1615
|
+
alias :delete_last :delete_last_value
|
|
1517
1616
|
|
|
1518
1617
|
# Deletes all values for the specified key.
|
|
1519
1618
|
#
|
|
@@ -1527,65 +1626,119 @@ class MultiRBTree < RBTree
|
|
|
1527
1626
|
# tree.insert(1, 'second')
|
|
1528
1627
|
# vals = tree.delete(1) # removes both values
|
|
1529
1628
|
# vals.size # => 2
|
|
1530
|
-
def
|
|
1531
|
-
z = @hash_index
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
remove_node(z)
|
|
1536
|
-
@size -= count
|
|
1537
|
-
z.value
|
|
1629
|
+
def delete_key(key)
|
|
1630
|
+
return nil unless (z = @hash_index[key])
|
|
1631
|
+
@value_count -= (value = z.value).size
|
|
1632
|
+
delete_indexed_node(z.key)
|
|
1633
|
+
value
|
|
1538
1634
|
end
|
|
1539
1635
|
|
|
1636
|
+
# Removes and returns the first key-value pair.
|
|
1637
|
+
#
|
|
1638
|
+
# @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
|
|
1639
|
+
# @example
|
|
1640
|
+
# tree = MultiRBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
|
|
1641
|
+
# tree.shift # => [1, "one"]
|
|
1540
1642
|
def shift
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
node.value.shift
|
|
1546
|
-
@size -= 1
|
|
1547
|
-
if node.value.empty?
|
|
1548
|
-
delete_node(key)
|
|
1549
|
-
end
|
|
1643
|
+
(key, vals = min_node&.pair) or return nil
|
|
1644
|
+
val = vals.shift
|
|
1645
|
+
vals.empty? && delete_indexed_node(key)
|
|
1646
|
+
@value_count -= 1
|
|
1550
1647
|
[key, val]
|
|
1551
1648
|
end
|
|
1552
1649
|
|
|
1650
|
+
# Removes and returns the last key-value pair.
|
|
1651
|
+
#
|
|
1652
|
+
# @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
|
|
1653
|
+
# @example
|
|
1654
|
+
# tree = MultiRBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
|
|
1655
|
+
# tree.pop # => [3, "three"]
|
|
1553
1656
|
def pop
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
n.value.pop
|
|
1559
|
-
@size -= 1
|
|
1560
|
-
if n.value.empty?
|
|
1561
|
-
delete_node(key)
|
|
1562
|
-
end
|
|
1657
|
+
(key, vals = max_node&.pair) or return nil
|
|
1658
|
+
val = vals.pop
|
|
1659
|
+
vals.empty? && delete_indexed_node(key)
|
|
1660
|
+
@value_count -= 1
|
|
1563
1661
|
[key, val]
|
|
1564
1662
|
end
|
|
1565
1663
|
|
|
1566
|
-
#
|
|
1664
|
+
# @!visibility private
|
|
1665
|
+
private
|
|
1666
|
+
|
|
1667
|
+
# Inserts a value for the given key.
|
|
1567
1668
|
#
|
|
1568
|
-
#
|
|
1569
|
-
#
|
|
1669
|
+
# If the key already exists, the value is appended to its list.
|
|
1670
|
+
# If the key doesn't exist, a new node is created.
|
|
1671
|
+
#
|
|
1672
|
+
# @param key [Object] the key (must implement <=>)
|
|
1673
|
+
# @param value [Object] the value to insert
|
|
1674
|
+
# @param overwrite [Boolean] ignored for MultiRBTree which always appends
|
|
1675
|
+
# @return [Boolean] always returns true
|
|
1570
1676
|
# @example
|
|
1571
1677
|
# tree = MultiRBTree.new
|
|
1572
1678
|
# tree.insert(1, 'first')
|
|
1573
|
-
# tree.insert(1, 'second')
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1679
|
+
# tree.insert(1, 'second') # adds another value for key 1
|
|
1680
|
+
def insert_entry(key, value, **)
|
|
1681
|
+
if (node = @hash_index[key])
|
|
1682
|
+
node.value << value
|
|
1683
|
+
@value_count += 1
|
|
1684
|
+
return true
|
|
1685
|
+
end
|
|
1686
|
+
y = @nil_node
|
|
1687
|
+
x = @root
|
|
1688
|
+
while x != @nil_node
|
|
1689
|
+
y = x
|
|
1690
|
+
cmp = key <=> x.key
|
|
1691
|
+
if cmp == 0
|
|
1692
|
+
x.value << value
|
|
1693
|
+
@value_count += 1
|
|
1694
|
+
return true
|
|
1695
|
+
elsif cmp < 0
|
|
1696
|
+
x = x.left
|
|
1697
|
+
else
|
|
1698
|
+
x = x.right
|
|
1699
|
+
end
|
|
1700
|
+
end
|
|
1701
|
+
z = allocate_node(key, [value], Node::RED, @nil_node, @nil_node, @nil_node)
|
|
1702
|
+
z.parent = y
|
|
1703
|
+
if y == @nil_node
|
|
1704
|
+
@root = z
|
|
1705
|
+
elsif (key <=> y.key) < 0
|
|
1706
|
+
y.left = z
|
|
1707
|
+
else
|
|
1708
|
+
y.right = z
|
|
1709
|
+
end
|
|
1710
|
+
z.left = @nil_node
|
|
1711
|
+
z.right = @nil_node
|
|
1712
|
+
z.color = Node::RED
|
|
1713
|
+
insert_fixup(z)
|
|
1714
|
+
@value_count += 1
|
|
1715
|
+
|
|
1716
|
+
if @min_node == @nil_node || (key <=> @min_node.key) < 0
|
|
1717
|
+
@min_node = z
|
|
1718
|
+
end
|
|
1719
|
+
|
|
1720
|
+
@hash_index[key] = z # Add to hash index
|
|
1721
|
+
true
|
|
1578
1722
|
end
|
|
1579
1723
|
|
|
1580
|
-
#
|
|
1581
|
-
|
|
1582
|
-
|
|
1724
|
+
# Traverses the tree in ascending order, yielding each key-value pair.
|
|
1725
|
+
#
|
|
1726
|
+
# @param range [Range] the range of keys to traverse
|
|
1727
|
+
# @yield [Array(Object, Object)] each key-value pair
|
|
1728
|
+
# @yieldparam key [Object] the key
|
|
1729
|
+
# @yieldparam val [Object] the value
|
|
1583
1730
|
def traverse_range_asc(...)
|
|
1584
|
-
super { |k, vals| vals.each { |v| yield k, v } }
|
|
1731
|
+
super { |k, vals| vals.each { |v| yield [k, v] } }
|
|
1585
1732
|
end
|
|
1586
1733
|
|
|
1734
|
+
# Traverses the tree in descending order, yielding each key-value pair.
|
|
1735
|
+
#
|
|
1736
|
+
# @param range [Range] the range of keys to traverse
|
|
1737
|
+
# @yield [Array(Object, Object)] each key-value pair
|
|
1738
|
+
# @yieldparam key [Object] the key
|
|
1739
|
+
# @yieldparam val [Object] the value
|
|
1587
1740
|
def traverse_range_desc(...)
|
|
1588
|
-
super { |k, vals| vals.reverse_each { |v| yield k, v } }
|
|
1741
|
+
super { |k, vals| vals.reverse_each { |v| yield [k, v] } }
|
|
1589
1742
|
end
|
|
1590
1743
|
end
|
|
1591
1744
|
|