rbtree-ruby 0.1.7 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8aa1d883925f6b7f608108f1f916598aa04be013aee415c06dfc7bda35d6986c
4
- data.tar.gz: e935f213100c933b42a3cf0d709809d5ca8d536db56d6e27a6b3de9681847ad9
3
+ metadata.gz: ea4c407bb808b5f0ce61e05d95bdb1b9a7efce1a6db4ef6c5688016d39eb66a1
4
+ data.tar.gz: 1dec0818d2844494de2daf36cca3b018d28589316b580d71879756e34ca3adb0
5
5
  SHA512:
6
- metadata.gz: 419f0270137b6a6ae39bd73d5ea0c4cc25ff0769c288619ee795d172e724040c6032c09c952745b9bb871ff082861c00ae879fa6a98a571414bad87c2534cb9a
7
- data.tar.gz: e403cc18d16ff9661a341fb326b3aadebc5d1a83b69ed03395b318cf6666d8de9dca24e88da2a9c231395aa7780ce57ed89902717ad1266bd1551e384872719f
6
+ metadata.gz: 654691a199723dd0b7426fea9165b372f4c71bcdadc8a58a90b76352b8eaade41145270ff6f88ffb37a4a22732a46b636d21515a07d4ae18b061c5d6fb154d53
7
+ data.tar.gz: 8e619ef4f92f440e92350748bfaadc80dc65f8a1daed06d6df1b73e20c4228ee943677496f56e9a8e413cb7081b8d98e6c7711a0b6ffe50fcbf8ab00bb65ed5a
data/CHANGELOG.md CHANGED
@@ -5,6 +5,20 @@ 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.0] - 2026-01-14
9
+
10
+ ### Added
11
+ - **MultiRBTree**: `nearest(key, last: false)` option to choose first or last value
12
+
13
+ ## [0.1.8] - 2026-01-14
14
+
15
+ ### Changed
16
+ - **Range Query Returns Enumerator**: `lt`, `lte`, `gt`, `gte`, `between` now return an `Enumerator` instead of an `Array` when no block is given
17
+ - Enables lazy evaluation: `tree.gt(100).lazy.take(5).to_a`
18
+ - Enables chaining: `tree.lt(50).map { |k, v| k }`
19
+ - Use `.to_a` to get an Array: `tree.lt(50).to_a`
20
+ - **Breaking**: Code using direct array access like `tree.lt(50)[0]` must change to `tree.lt(50).first`
21
+
8
22
  ## [0.1.7] - 2026-01-14
9
23
 
10
24
  ### Added
@@ -107,9 +121,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
107
121
  - ASCII diagrams for tree rotation operations
108
122
  - MIT License (Copyright © 2026 Masahito Suzuki)
109
123
 
124
+ [0.2.0]: https://github.com/firelzrd/rbtree-ruby/releases/tag/v0.2.0
125
+ [0.1.8]: https://github.com/firelzrd/rbtree-ruby/releases/tag/v0.1.8
110
126
  [0.1.7]: https://github.com/firelzrd/rbtree-ruby/releases/tag/v0.1.7
111
127
  [0.1.6]: https://github.com/firelzrd/rbtree-ruby/releases/tag/v0.1.6
112
- [0.1.5]: https://github.com/firelzrd/rbtree-ruby/releases/tag/v0.1.5
113
- [0.1.4]: https://github.com/firelzrd/rbtree-ruby/releases/tag/v0.1.4
114
- [0.1.3]: https://github.com/firelzrd/rbtree-ruby/releases/tag/v0.1.3
115
- [0.1.2]: https://github.com/firelzrd/rbtree-ruby/releases/tag/v0.1.2
data/README.ja.md ADDED
@@ -0,0 +1,275 @@
1
+ # rbtree-ruby
2
+
3
+ 🌍 *[English](README.md) | [日本語](README.ja.md)*
4
+
5
+ Red-Black Tree(赤黒木)データ構造のピュアRuby実装です。挿入、削除、検索操作がO(log n)の時間計算量で実行できる、効率的な順序付きキーバリューストレージを提供します。
6
+
7
+ ## 特徴
8
+
9
+ - **自己平衡二分探索木**: 赤黒木の性質により最適なパフォーマンスを維持
10
+ - **順序付き操作**: 効率的な範囲クエリ、最小/最大値の取得、ソート済みイテレーション
11
+ - **複数値サポート**: `MultiRBTree`クラスで同一キーに複数の値を格納可能
12
+ - **ピュアRuby**: C拡張不要、あらゆるRuby実装で動作
13
+ - **充実したドキュメント**: 使用例付きの包括的なRDocドキュメント
14
+
15
+ ## インストール
16
+
17
+ Gemfileに以下を追加:
18
+
19
+ ```ruby
20
+ gem 'rbtree-ruby'
21
+ ```
22
+
23
+ 実行:
24
+
25
+ ```bash
26
+ bundle install
27
+ ```
28
+
29
+ または直接インストール:
30
+
31
+ ```bash
32
+ gem install rbtree-ruby
33
+ ```
34
+
35
+ ## 使い方
36
+
37
+ ### 基本的なRBTree
38
+
39
+ ```ruby
40
+ require 'rbtree'
41
+
42
+ # 空のツリーを作成
43
+ tree = RBTree.new
44
+
45
+ # データで初期化
46
+ tree = RBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
47
+ tree = RBTree[[5, 'five'], [4, 'four']]
48
+
49
+ # 値の挿入と取得
50
+ tree.insert(10, 'ten')
51
+ tree[20] = 'twenty'
52
+ puts tree[10] # => "ten"
53
+
54
+ # ソート順でイテレーション
55
+ tree.each { |key, value| puts "#{key}: #{value}" }
56
+ # 出力:
57
+ # 1: one
58
+ # 2: two
59
+ # 3: three
60
+ # 10: ten
61
+ # 20: twenty
62
+
63
+ # 最小値と最大値
64
+ tree.min # => [1, "one"]
65
+ tree.max # => [20, "twenty"]
66
+
67
+ # 範囲クエリ(Enumeratorを返す、配列には.to_aを使用)
68
+ tree.lt(10).to_a # => [[1, "one"], [2, "two"], [3, "three"]]
69
+ tree.gte(10).to_a # => [[10, "ten"], [20, "twenty"]]
70
+ tree.between(2, 10).to_a # => [[2, "two"], [3, "three"], [10, "ten"]]
71
+
72
+ # shiftとpop
73
+ tree.shift # => [1, "one"] (最小値を削除)
74
+ tree.pop # => [20, "twenty"] (最大値を削除)
75
+
76
+ # 削除
77
+ tree.delete(3) # => "three"
78
+
79
+ # キーの存在確認
80
+ tree.has_key?(2) # => true
81
+ tree.size # => 2
82
+ ```
83
+
84
+ ### MultiRBTree(重複キー対応)
85
+
86
+ ```ruby
87
+ require 'rbtree'
88
+
89
+ tree = MultiRBTree.new
90
+
91
+ # 同じキーに複数の値を挿入
92
+ tree.insert(1, 'first one')
93
+ tree.insert(1, 'second one')
94
+ tree.insert(1, 'third one')
95
+ tree.insert(2, 'two')
96
+
97
+ tree.size # => 4 (キーバリューペアの総数)
98
+
99
+ # 最初の値を取得
100
+ tree.get(1) # => "first one"
101
+ tree[1] # => "first one"
102
+
103
+ # キーの全ての値を取得
104
+ tree.get_all(1) # => ["first one", "second one", "third one"]
105
+
106
+ # 全キーバリューペアをイテレーション
107
+ tree.each { |k, v| puts "#{k}: #{v}" }
108
+ # 出力:
109
+ # 1: first one
110
+ # 1: second one
111
+ # 1: third one
112
+ # 2: two
113
+
114
+ # 最初の値のみ削除
115
+ tree.delete_one(1) # => "first one"
116
+ tree.get(1) # => "second one"
117
+
118
+ # キーの全ての値を削除
119
+ tree.delete(1) # 残りの値を全て削除
120
+ ```
121
+
122
+ ### 最近傍キー検索
123
+
124
+ ```ruby
125
+ tree = RBTree.new({1 => 'one', 5 => 'five', 10 => 'ten'})
126
+
127
+ tree.nearest(4) # => [5, "five"] (4に最も近いキー)
128
+ tree.nearest(7) # => [5, "five"] (同距離の場合は小さいキー)
129
+ tree.nearest(8) # => [10, "ten"]
130
+ ```
131
+
132
+ ### 前後キー検索
133
+
134
+ ```ruby
135
+ tree = RBTree.new({1 => 'one', 3 => 'three', 5 => 'five', 7 => 'seven'})
136
+
137
+ tree.prev(5) # => [3, "three"] (5より小さい最大のキー)
138
+ tree.succ(5) # => [7, "seven"] (5より大きい最小のキー)
139
+
140
+ # キーが存在しなくても動作
141
+ tree.prev(4) # => [3, "three"] (4は存在しない、4未満の最大キーを返す)
142
+ tree.succ(4) # => [5, "five"] (4は存在しない、4より大きい最小キーを返す)
143
+
144
+ # 境界ではnilを返す
145
+ tree.prev(1) # => nil (1より小さいキーなし)
146
+ tree.succ(7) # => nil (7より大きいキーなし)
147
+ ```
148
+
149
+ ### 逆順範囲クエリ
150
+
151
+ 範囲クエリは`Enumerator`を返し(配列には`.to_a`を使用)、`:reverse`オプションをサポート:
152
+
153
+ ```ruby
154
+ tree = RBTree.new({1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four'})
155
+
156
+ tree.lt(3).to_a # => [[1, "one"], [2, "two"]]
157
+ tree.lt(3, reverse: true).to_a # => [[2, "two"], [1, "one"]]
158
+ tree.lt(3).first # => [1, "one"] (遅延評価、配列は作成されない)
159
+
160
+ # 遅延評価
161
+ tree.gt(0).lazy.take(2).to_a # => [[1, "one"], [2, "two"]] (最初の2件のみ計算)
162
+ ```
163
+
164
+ ### MultiRBTree 値配列アクセス
165
+
166
+ 複数の値を持つキーで、どの値にアクセスするか選択:
167
+
168
+ ```ruby
169
+ tree = MultiRBTree.new
170
+ tree.insert(1, 'first')
171
+ tree.insert(1, 'second')
172
+ tree.insert(1, 'third')
173
+
174
+ # 最初または最後の値にアクセス
175
+ tree.get(1) # => "first"
176
+ tree.get(1, last: true) # => "third"
177
+ tree.get_first(1) # => "first"
178
+ tree.get_last(1) # => "third"
179
+
180
+ # どちらの端からも削除可能
181
+ tree.delete_first(1) # => "first"
182
+ tree.delete_last(1) # => "third"
183
+ tree.get(1) # => "second"
184
+
185
+ # min/maxの:lastオプション
186
+ tree.insert(2, 'a')
187
+ tree.insert(2, 'b')
188
+ tree.min # => [1, "second"] (最小キーの最初の値)
189
+ tree.max(last: true) # => [2, "b"] (最大キーの最後の値)
190
+ ```
191
+
192
+ ## パフォーマンス
193
+
194
+ 主要な操作は**O(log n)**時間で実行:
195
+
196
+ - `insert(key, value)` - O(log n)
197
+ - `delete(key)` - O(log n)
198
+ - `get(key)` / `[]` - **O(1)** (ハイブリッドハッシュインデックス)
199
+ - `has_key?` - **O(1)** (ハイブリッドハッシュインデックス)
200
+ - `min` - **O(1)**
201
+ - `max` - O(log n)
202
+ - `shift` / `pop` - O(log n)
203
+ - `prev` / `succ` - O(log n)、O(1)ハッシュチェック付き
204
+
205
+ 全要素のイテレーションはO(n)時間。
206
+
207
+ ### メモリ効率
208
+
209
+ RBTreeは内部的な**メモリプール**を使用してノードオブジェクトを再利用:
210
+ - 頻繁な挿入・削除時のGC負荷を大幅に削減
211
+ - 100,000回の循環操作ベンチマークで**GC時間0.0秒**を達成
212
+
213
+ ### RBTree vs Hash vs Array
214
+
215
+ 順序付き操作と空間的操作において、RBTreeは単に速いだけでなく、全く異なるクラスの性能を発揮。**50万件**でのベンチマーク:
216
+
217
+ | 操作 | RBTree | Hash/Array | 高速化 | 理由 |
218
+ |-----|--------|------------|-------|-----|
219
+ | **最近傍検索** | **O(log n)** | O(n) スキャン | **〜8,600倍高速** | 二分探索 vs 全件スキャン |
220
+ | **範囲クエリ** | **O(log n + k)** | O(n) フィルター | **〜540倍高速** | 部分木へ直接ジャンプ vs 全件スキャン |
221
+ | **最小値抽出** | **O(log n)** | O(n) 検索 | **〜160倍高速** | 連続的なリバランス vs 全件スキャン |
222
+ | **ソート済みイテレーション** | **O(n)** | O(n log n) | **無料** | 常にソート済み vs 明示的な`sort` |
223
+ | **キー検索** | **O(1)** | O(1) | **同等** | ハイブリッドハッシュインデックス |
224
+
225
+ ### RBTreeを使うべき場面
226
+
227
+ ✅ **RBTreeが適している場合:**
228
+ - キー順でのイテレーション
229
+ - 高速なmin/max取得
230
+ - 範囲クエリ(`between`, `lt`, `gt`, `lte`, `gte`)
231
+ - 最近傍キー検索
232
+ - 優先度キュー的な動作(キー順でshift/pop)
233
+
234
+ ✅ **Hashが適している場合:**
235
+ - 高速なキーバリュー検索のみ(RBTreeも同等に高速!)
236
+ - 順序付けが不要
237
+
238
+ ## APIドキュメント
239
+
240
+ 完全なRDocドキュメントを生成:
241
+
242
+ ```bash
243
+ rdoc lib/rbtree.rb
244
+ ```
245
+
246
+ `doc/index.html`をブラウザで開いてください。
247
+
248
+ ## 開発
249
+
250
+ リポジトリをチェックアウト後、`bundle install`で依存関係をインストール:
251
+
252
+ ```bash
253
+ # RDocドキュメント生成
254
+ rake rdoc
255
+
256
+ # gemのビルド
257
+ rake build
258
+
259
+ # ローカルインストール
260
+ rake install
261
+ ```
262
+
263
+ ## コントリビューション
264
+
265
+ バグ報告やプルリクエストはGitHubで受け付けています: https://github.com/firelzrd/rbtree-ruby
266
+
267
+ ## ライセンス
268
+
269
+ [MIT License](https://opensource.org/licenses/MIT)でオープンソースとして公開。
270
+
271
+ ## 作者
272
+
273
+ Masahito Suzuki (firelzrd@gmail.com)
274
+
275
+ Copyright © 2026 Masahito Suzuki
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # rbtree-ruby
2
2
 
3
+ 🌍 *[English](README.md) | [日本語](README.ja.md)*
4
+
3
5
  A pure Ruby implementation of the Red-Black Tree data structure, providing efficient ordered key-value storage with O(log n) time complexity for insertion, deletion, and lookup operations.
4
6
 
5
7
  ## Features
@@ -62,10 +64,10 @@ tree.each { |key, value| puts "#{key}: #{value}" }
62
64
  tree.min # => [1, "one"]
63
65
  tree.max # => [20, "twenty"]
64
66
 
65
- # Range queries
66
- tree.lt(10) # => [[1, "one"], [2, "two"], [3, "three"]]
67
- tree.gte(10) # => [[10, "ten"], [20, "twenty"]]
68
- tree.between(2, 10) # => [[2, "two"], [3, "three"], [10, "ten"]]
67
+ # Range queries (return Enumerator, use .to_a for Array)
68
+ tree.lt(10).to_a # => [[1, "one"], [2, "two"], [3, "three"]]
69
+ tree.gte(10).to_a # => [[10, "ten"], [20, "twenty"]]
70
+ tree.between(2, 10).to_a # => [[2, "two"], [3, "three"], [10, "ten"]]
69
71
 
70
72
  # Shift and pop
71
73
  tree.shift # => [1, "one"] (removes minimum)
@@ -148,15 +150,17 @@ tree.succ(7) # => nil (no key larger than 7)
148
150
 
149
151
  ### Reverse Range Queries
150
152
 
151
- All range queries support a `:reverse` option to iterate in descending order:
153
+ All range queries return an `Enumerator` (use `.to_a` for Array) and support a `:reverse` option:
152
154
 
153
155
  ```ruby
154
156
  tree = RBTree.new({1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four'})
155
157
 
156
- tree.lt(3) # => [[1, "one"], [2, "two"]]
157
- tree.lt(3, reverse: true) # => [[2, "two"], [1, "one"]]
158
+ tree.lt(3).to_a # => [[1, "one"], [2, "two"]]
159
+ tree.lt(3, reverse: true).to_a # => [[2, "two"], [1, "one"]]
160
+ tree.lt(3).first # => [1, "one"] (lazy, no array created)
158
161
 
159
- tree.between(1, 4, reverse: true) # => [[4, "four"], [3, "three"], [2, "two"], [1, "one"]]
162
+ # Lazy evaluation
163
+ tree.gt(0).lazy.take(2).to_a # => [[1, "one"], [2, "two"]] (only computes first 2)
160
164
  ```
161
165
 
162
166
  ### MultiRBTree Value Array Access
@@ -2,5 +2,5 @@
2
2
 
3
3
  class RBTree
4
4
  # The version of the rbtree-ruby gem
5
- VERSION = "0.1.7"
5
+ VERSION = "0.2.0"
6
6
  end
data/lib/rbtree.rb CHANGED
@@ -331,28 +331,20 @@ class RBTree
331
331
  # @param key [Object] the upper bound (exclusive)
332
332
  # @param reverse [Boolean] if true, iterate in descending order (default: false)
333
333
  # @yield [key, value] each matching key-value pair (if block given)
334
- # @return [Array<Array(Object, Object)>, RBTree] array of [key, value] pairs if no block, self otherwise
334
+ # @return [Enumerator, RBTree] Enumerator if no block given, self otherwise
335
335
  # @example
336
336
  # tree = RBTree.new({1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four'})
337
- # tree.lt(3) # => [[1, "one"], [2, "two"]]
338
- # tree.lt(3, reverse: true) # => [[2, "two"], [1, "one"]]
337
+ # tree.lt(3).to_a # => [[1, "one"], [2, "two"]]
338
+ # tree.lt(3, reverse: true).first # => [2, "two"]
339
+ # tree.lt(3) { |k, v| puts k } # prints keys, returns self
339
340
  def lt(key, reverse: false, &block)
340
- if block_given?
341
- if reverse
342
- traverse_lt_desc(@root, key, &block)
343
- else
344
- traverse_lt(@root, key, &block)
345
- end
346
- self
341
+ return enum_for(:lt, key, reverse: reverse) unless block_given?
342
+ if reverse
343
+ traverse_lt_desc(@root, key, &block)
347
344
  else
348
- res = []
349
- if reverse
350
- traverse_lt_desc(@root, key) { |k, v| res << [k, v] }
351
- else
352
- traverse_lt(@root, key) { |k, v| res << [k, v] }
353
- end
354
- res
345
+ traverse_lt(@root, key, &block)
355
346
  end
347
+ self
356
348
  end
357
349
 
358
350
  # Retrieves all key-value pairs with keys less than or equal to the specified key.
@@ -360,28 +352,19 @@ class RBTree
360
352
  # @param key [Object] the upper bound (inclusive)
361
353
  # @param reverse [Boolean] if true, iterate in descending order (default: false)
362
354
  # @yield [key, value] each matching key-value pair (if block given)
363
- # @return [Array<Array(Object, Object)>, RBTree] array of [key, value] pairs if no block, self otherwise
355
+ # @return [Enumerator, RBTree] Enumerator if no block given, self otherwise
364
356
  # @example
365
357
  # tree = RBTree.new({1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four'})
366
- # tree.lte(3) # => [[1, "one"], [2, "two"], [3, "three"]]
367
- # tree.lte(3, reverse: true) # => [[3, "three"], [2, "two"], [1, "one"]]
358
+ # tree.lte(3).to_a # => [[1, "one"], [2, "two"], [3, "three"]]
359
+ # tree.lte(3, reverse: true).first # => [3, "three"]
368
360
  def lte(key, reverse: false, &block)
369
- if block_given?
370
- if reverse
371
- traverse_lte_desc(@root, key, &block)
372
- else
373
- traverse_lte(@root, key, &block)
374
- end
375
- self
361
+ return enum_for(:lte, key, reverse: reverse) unless block_given?
362
+ if reverse
363
+ traverse_lte_desc(@root, key, &block)
376
364
  else
377
- res = []
378
- if reverse
379
- traverse_lte_desc(@root, key) { |k, v| res << [k, v] }
380
- else
381
- traverse_lte(@root, key) { |k, v| res << [k, v] }
382
- end
383
- res
365
+ traverse_lte(@root, key, &block)
384
366
  end
367
+ self
385
368
  end
386
369
 
387
370
  # Retrieves all key-value pairs with keys greater than the specified key.
@@ -389,28 +372,19 @@ class RBTree
389
372
  # @param key [Object] the lower bound (exclusive)
390
373
  # @param reverse [Boolean] if true, iterate in descending order (default: false)
391
374
  # @yield [key, value] each matching key-value pair (if block given)
392
- # @return [Array<Array(Object, Object)>, RBTree] array of [key, value] pairs if no block, self otherwise
375
+ # @return [Enumerator, RBTree] Enumerator if no block given, self otherwise
393
376
  # @example
394
377
  # tree = RBTree.new({1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four'})
395
- # tree.gt(2) # => [[3, "three"], [4, "four"]]
396
- # tree.gt(2, reverse: true) # => [[4, "four"], [3, "three"]]
378
+ # tree.gt(2).to_a # => [[3, "three"], [4, "four"]]
379
+ # tree.gt(2, reverse: true).first # => [4, "four"]
397
380
  def gt(key, reverse: false, &block)
398
- if block_given?
399
- if reverse
400
- traverse_gt_desc(@root, key, &block)
401
- else
402
- traverse_gt(@root, key, &block)
403
- end
404
- self
381
+ return enum_for(:gt, key, reverse: reverse) unless block_given?
382
+ if reverse
383
+ traverse_gt_desc(@root, key, &block)
405
384
  else
406
- res = []
407
- if reverse
408
- traverse_gt_desc(@root, key) { |k, v| res << [k, v] }
409
- else
410
- traverse_gt(@root, key) { |k, v| res << [k, v] }
411
- end
412
- res
385
+ traverse_gt(@root, key, &block)
413
386
  end
387
+ self
414
388
  end
415
389
 
416
390
  # Retrieves all key-value pairs with keys greater than or equal to the specified key.
@@ -418,28 +392,19 @@ class RBTree
418
392
  # @param key [Object] the lower bound (inclusive)
419
393
  # @param reverse [Boolean] if true, iterate in descending order (default: false)
420
394
  # @yield [key, value] each matching key-value pair (if block given)
421
- # @return [Array<Array(Object, Object)>, RBTree] array of [key, value] pairs if no block, self otherwise
395
+ # @return [Enumerator, RBTree] Enumerator if no block given, self otherwise
422
396
  # @example
423
397
  # tree = RBTree.new({1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four'})
424
- # tree.gte(2) # => [[2, "two"], [3, "three"], [4, "four"]]
425
- # tree.gte(2, reverse: true) # => [[4, "four"], [3, "three"], [2, "two"]]
398
+ # tree.gte(2).to_a # => [[2, "two"], [3, "three"], [4, "four"]]
399
+ # tree.gte(2, reverse: true).first # => [4, "four"]
426
400
  def gte(key, reverse: false, &block)
427
- if block_given?
428
- if reverse
429
- traverse_gte_desc(@root, key, &block)
430
- else
431
- traverse_gte(@root, key, &block)
432
- end
433
- self
401
+ return enum_for(:gte, key, reverse: reverse) unless block_given?
402
+ if reverse
403
+ traverse_gte_desc(@root, key, &block)
434
404
  else
435
- res = []
436
- if reverse
437
- traverse_gte_desc(@root, key) { |k, v| res << [k, v] }
438
- else
439
- traverse_gte(@root, key) { |k, v| res << [k, v] }
440
- end
441
- res
405
+ traverse_gte(@root, key, &block)
442
406
  end
407
+ self
443
408
  end
444
409
 
445
410
  # Retrieves all key-value pairs with keys within the specified range.
@@ -450,29 +415,19 @@ class RBTree
450
415
  # @param include_max [Boolean] whether to include the upper bound (default: true)
451
416
  # @param reverse [Boolean] if true, iterate in descending order (default: false)
452
417
  # @yield [key, value] each matching key-value pair (if block given)
453
- # @return [Array<Array(Object, Object)>, RBTree] array of [key, value] pairs if no block, self otherwise
418
+ # @return [Enumerator, RBTree] Enumerator if no block given, self otherwise
454
419
  # @example
455
420
  # tree = RBTree.new({1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four', 5 => 'five'})
456
- # tree.between(2, 4) # => [[2, "two"], [3, "three"], [4, "four"]]
457
- # tree.between(2, 4, include_min: false) # => [[3, "three"], [4, "four"]]
458
- # tree.between(2, 4, reverse: true) # => [[4, "four"], [3, "three"], [2, "two"]]
421
+ # tree.between(2, 4).to_a # => [[2, "two"], [3, "three"], [4, "four"]]
422
+ # tree.between(2, 4, reverse: true).first # => [4, "four"]
459
423
  def between(min, max, include_min: true, include_max: true, reverse: false, &block)
460
- if block_given?
461
- if reverse
462
- traverse_between_desc(@root, min, max, include_min, include_max, &block)
463
- else
464
- traverse_between(@root, min, max, include_min, include_max, &block)
465
- end
466
- self
424
+ return enum_for(:between, min, max, include_min: include_min, include_max: include_max, reverse: reverse) unless block_given?
425
+ if reverse
426
+ traverse_between_desc(@root, min, max, include_min, include_max, &block)
467
427
  else
468
- res = []
469
- if reverse
470
- traverse_between_desc(@root, min, max, include_min, include_max) { |k, v| res << [k, v] }
471
- else
472
- traverse_between(@root, min, max, include_min, include_max) { |k, v| res << [k, v] }
473
- end
474
- res
428
+ traverse_between(@root, min, max, include_min, include_max, &block)
475
429
  end
430
+ self
476
431
  end
477
432
 
478
433
  # Returns the key-value pair with the key closest to the given key.
@@ -1506,9 +1461,10 @@ class MultiRBTree < RBTree
1506
1461
  [n.key, last ? n.value.last : n.value.first]
1507
1462
  end
1508
1463
 
1509
- def nearest(key)
1464
+ def nearest(key, last: false)
1510
1465
  n = find_nearest_node(key)
1511
- n == @nil_node || n.value.empty? ? nil : [n.key, n.value.first]
1466
+ return nil if n == @nil_node || n.value.empty?
1467
+ [n.key, last ? n.value.last : n.value.first]
1512
1468
  end
1513
1469
 
1514
1470
  def prev(key, last: false)
data/rbtree-ruby.gemspec CHANGED
@@ -8,11 +8,12 @@ Gem::Specification.new do |spec|
8
8
  spec.authors = ["Masahito Suzuki"]
9
9
  spec.email = ["firelzrd@gmail.com"]
10
10
 
11
- spec.summary = "A pure Ruby implementation of Red-Black Tree with multi-value support"
11
+ spec.summary = "A pure Ruby Red-Black Tree with O(1) lookup, range queries, and multi-value support"
12
12
  spec.description = <<~DESC
13
- RBTree is a pure Ruby implementation of the Red-Black Tree data structure,
14
- providing efficient ordered key-value storage with O(log n) operations.
15
- Includes MultiRBTree for handling duplicate keys with linked lists.
13
+ A high-performance pure Ruby Red-Black Tree implementation. Features: O(1) key
14
+ lookup via hybrid hash index, O(log n) insert/delete, lazy Enumerator-based
15
+ range queries (lt/gt/between), nearest/prev/succ search, memory-efficient node
16
+ pooling, and MultiRBTree for duplicate keys with first/last value access.
16
17
  DESC
17
18
  spec.homepage = "https://github.com/firelzrd/rbtree-ruby"
18
19
  spec.license = "MIT"
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.1.7
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Masahito Suzuki
@@ -10,9 +10,10 @@ cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies: []
12
12
  description: |
13
- RBTree is a pure Ruby implementation of the Red-Black Tree data structure,
14
- providing efficient ordered key-value storage with O(log n) operations.
15
- Includes MultiRBTree for handling duplicate keys with linked lists.
13
+ A high-performance pure Ruby Red-Black Tree implementation. Features: O(1) key
14
+ lookup via hybrid hash index, O(log n) insert/delete, lazy Enumerator-based
15
+ range queries (lt/gt/between), nearest/prev/succ search, memory-efficient node
16
+ pooling, and MultiRBTree for duplicate keys with first/last value access.
16
17
  email:
17
18
  - firelzrd@gmail.com
18
19
  executables: []
@@ -21,6 +22,7 @@ extra_rdoc_files: []
21
22
  files:
22
23
  - CHANGELOG.md
23
24
  - LICENSE
25
+ - README.ja.md
24
26
  - README.md
25
27
  - Rakefile
26
28
  - lib/rbtree.rb
@@ -49,5 +51,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
49
51
  requirements: []
50
52
  rubygems_version: 4.0.3
51
53
  specification_version: 4
52
- summary: A pure Ruby implementation of Red-Black Tree with multi-value support
54
+ summary: A pure Ruby Red-Black Tree with O(1) lookup, range queries, and multi-value
55
+ support
53
56
  test_files: []