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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f3c97bfa59aaaa7bbc03f272fdc5e383b258f529134f1d2a79fd3758d1d53b02
4
- data.tar.gz: fa9c8df14da95bf4224164d720c90981c1c68ef96e5cb544007327b9a1564b11
3
+ metadata.gz: df8aaee3fedf309a0079082fa38c10e3748bc68873131800e13f30dee1202273
4
+ data.tar.gz: 5e6dd162b0ebb1b50929d9127c4ac57598c7391ecf63a7d1dca7e42107d4ca3a
5
5
  SHA512:
6
- metadata.gz: e856b4d10d326c3d3261d21044db760b41447dd01e1eb22bff4dfe1ac07e71f709792b75a9ee48ddc3195f06993fd86e8434511b3f2f0eaafbcf0827da05aa1e
7
- data.tar.gz: 10e8c1af8787b201c73a64557ba86304867b601daae13ad816771b87e52a81e30bc94dbeda5accc1e224a55d397ae28e0325918d61d8d4db40ee09cdd83876fa
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.get(1) # => "first one"
111
+ tree.value(1) # => "first one"
112
112
  tree[1] # => "first one"
113
113
 
114
114
  # キーの全ての値を取得(Enumeratorを返す)
115
- tree.get_all(1).to_a # => ["first one", "second one", "third one"]
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.delete_one(1) # => "first one"
127
- tree.get(1) # => "second one"
126
+ tree.delete_value(1) # => "first one"
127
+ tree.value(1) # => "second one"
128
128
 
129
129
  # キーの全ての値を削除
130
- tree.delete(1) # 残りの値を全て削除
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.get(1) # => "first"
189
- tree.get(1, last: true) # => "third"
190
- tree.get_first(1) # => "first"
191
- tree.get_last(1) # => "third"
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.delete_first(1) # => "first"
195
- tree.delete_last(1) # => "third"
196
- tree.get(1) # => "second"
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
- - `get(key)` / `[]` - **O(1)** (内部ハッシュインデックスによる超高速アクセス)
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.get(1) # => "first one"
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.get_all(1).to_a # => ["first one", "second one", "third one"]
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.delete_one(1) # => "first one"
127
- tree.get(1) # => "second one"
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.delete(1) # removes all remaining values
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.get(1) # => "first"
189
- tree.get(1, last: true) # => "third"
190
- tree.get_first(1) # => "first"
191
- tree.get_last(1) # => "third"
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.delete_first(1) # => "first"
195
- tree.delete_last(1) # => "third"
196
- tree.get(1) # => "second"
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
- - `get(key)` / `[]` - **O(1)** (hybrid hash index)
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)
@@ -2,5 +2,5 @@
2
2
 
3
3
  class RBTree
4
4
  # The version of the rbtree-ruby gem
5
- VERSION = "0.2.3"
5
+ VERSION = "0.3.1"
6
6
  end
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 :size
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
- @size = 0
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? = @root == @nil_node
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 = find_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 = find_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.has_key?(1) # => true
138
- # tree.has_key?(3) # => false
139
- def has_key?(key)
140
- @hash_index.key?(key)
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 get(key)
153
- @hash_index[key]&.value
154
- end
155
- alias_method :[], :get
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
- return nil unless key.respond_to?(:-)
171
- n = find_nearest_node(key)
172
- n == @nil_node ? nil : n.pair
173
- end
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
- n = find_predecessor_node(key)
189
- n == @nil_node ? nil : n.pair
190
- end
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
- alias_method :[]=, :insert
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 delete(key)
282
- value = delete_node(key)
283
- return nil unless value
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 if @min_node == @nil_node
297
- result = [@min_node.key, @min_node.value]
298
- delete(@min_node.key)
299
- result
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
- return nil if n == @nil_node
312
- result = n.pair
394
+ return nil unless (n = rightmost(@root)) != @nil_node
395
+ pair = n.pair
313
396
  delete(n.key)
314
- result
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
- @size = 0
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) = each(reverse: true, safe: safe, &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
- if @size > 0
496
- content = first(5).map { |k, v| "#{k.inspect}=>#{v.inspect}" }.join(", ")
497
- suffix = @size > 5 ? ", ..." : ""
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 protected
521
- protected
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 delete_node(key)
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 remove_node(z)
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 == @nil_node ? nil : @min_node.pair
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)) == @nil_node ? nil : n.pair
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
- if (node = @node_pool.pop)
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 (`delete_one`) vs. all deletions (`delete`)
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)+, +get_first(key)+ - returns first value (oldest)
1318
- # * +get(key, last: true)+, +get_last(key)+ - returns last value (newest)
1319
- # * +delete_one(key)+, +delete_first(key)+ - removes first value
1320
- # * +delete_one(key, last: true)+, +delete_last(key)+ - removes last value
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.get_all(1) # => ["first one", "second one"] (all values)
1446
+ # tree.values(1) # => ["first one", "second one"] (all values)
1355
1447
  #
1356
- # tree.delete_one(1) # removes only "first one"
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 min(last: false)
1365
- return nil if @min_node == @nil_node || @min_node.value.empty?
1366
- [@min_node.key, last ? @min_node.value.last : @min_node.value.first]
1456
+ def initialize(*args, **kwargs)
1457
+ @value_count = 0
1458
+ super
1367
1459
  end
1368
1460
 
1369
- def max(last: false)
1370
- n = rightmost(@root)
1371
- return nil if n == @nil_node || n.value.empty?
1372
- [n.key, last ? n.value.last : n.value.first]
1373
- end
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 get(key, last: false)
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 get_first(key) = get(key, last: false)
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 get_last(key) = get(key, last: true)
1521
+ def last_value(key) = value(key, last: true)
1522
+ alias :get_last :last_value
1403
1523
 
1404
- def nearest(key, last: false)
1405
- n = find_nearest_node(key)
1406
- return nil if n == @nil_node || n.value.empty?
1407
- [n.key, last ? n.value.last : n.value.first]
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
- def prev(key, last: false)
1411
- pair = super(key)
1412
- return nil unless pair
1413
- [pair[0], last ? pair[1].last : pair[1].first]
1414
- end
1415
-
1416
- def succ(key, last: false)
1417
- pair = super(key)
1418
- return nil unless pair
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
- # Inserts a value for the given key.
1549
+ # Returns the previous key-value pair without removing it.
1423
1550
  #
1424
- # If the key already exists, the value is appended to its list.
1425
- # If the key doesn't exist, a new node is created.
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 (must implement <=>)
1428
- # @param value [Object] the value to insert
1429
- # @param overwrite [Boolean] ignored for MultiRBTree which always appends
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.insert(1, 'first')
1434
- # tree.insert(1, 'second') # adds another value for key 1
1435
- def insert_entry(key, value, **)
1436
- if (node = @hash_index[key])
1437
- node.value << value
1438
- @size += 1
1439
- return true
1440
- end
1441
- y = @nil_node
1442
- x = @root
1443
- while x != @nil_node
1444
- y = x
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.delete_one(1) # => "first"
1492
- # tree.delete_one(1, last: true) # => "second" (if more values existed)
1493
- def delete_one(key, last: false)
1494
- z = @hash_index[key] # O(1) lookup
1495
- return nil unless z
1496
-
1497
- value = last ? z.value.pop : z.value.shift
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 delete_first(key) = delete_one(key, last: false)
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 delete_last(key) = delete_one(key, last: true)
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 delete(key)
1531
- z = @hash_index.delete(key) # O(1) lookup and remove from index
1532
- return nil unless z
1533
-
1534
- count = z.value.size
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
- return nil if @min_node == @nil_node
1542
- node = @min_node
1543
- key = node.key
1544
- val = node.value.first
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
- n = rightmost(@root)
1555
- return nil if n == @nil_node
1556
- key = n.key
1557
- val = n.value.last
1558
- n.value.pop
1559
- @size -= 1
1560
- if n.value.empty?
1561
- delete_node(key)
1562
- end
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
- # Retrieves all values associated with the given key.
1664
+ # @!visibility private
1665
+ private
1666
+
1667
+ # Inserts a value for the given key.
1567
1668
  #
1568
- # @param key [Object] the key to look up
1569
- # @return [Array, nil] an Array containing all values, or nil if not found
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
- # tree.get_all(1).to_a # => ["first", "second"]
1575
- def get_all(key)
1576
- return enum_for(:get_all, key) unless block_given?
1577
- @hash_index[key]&.value&.each { |v| yield v }
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
- # @!visibility protected
1581
- protected
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
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rbtree-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Masahito Suzuki