rbtree-ruby 0.1.8 → 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: ad4ff4e15079d2034a111e0180f1abbf5f433283de5c125f45569f9b69f558fc
4
- data.tar.gz: 7355e1ae3964e79aa8d110c52e38672641c8d67ac1cb4cfbbd974fe6298f07f7
3
+ metadata.gz: ea4c407bb808b5f0ce61e05d95bdb1b9a7efce1a6db4ef6c5688016d39eb66a1
4
+ data.tar.gz: 1dec0818d2844494de2daf36cca3b018d28589316b580d71879756e34ca3adb0
5
5
  SHA512:
6
- metadata.gz: e62ddc40bfc16d4afaf9430b679b03cfb50e89d3a02d7ab43a190b168015d4c6605baf579cc55abc0d42db207465538f99e81618beca873a1b4c654d1ab0c72f
7
- data.tar.gz: d11f0258d1ea5ea2686cc8bb581eb3b5c524554bf2182d68d54759e592d58d57e463bfa87b13dbabb67e68becfa8648108b267751791a1877e49bc7c6e2f6a06
6
+ metadata.gz: 654691a199723dd0b7426fea9165b372f4c71bcdadc8a58a90b76352b8eaade41145270ff6f88ffb37a4a22732a46b636d21515a07d4ae18b061c5d6fb154d53
7
+ data.tar.gz: 8e619ef4f92f440e92350748bfaadc80dc65f8a1daed06d6df1b73e20c4228ee943677496f56e9a8e413cb7081b8d98e6c7711a0b6ffe50fcbf8ab00bb65ed5a
data/CHANGELOG.md CHANGED
@@ -5,6 +5,11 @@ 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
+
8
13
  ## [0.1.8] - 2026-01-14
9
14
 
10
15
  ### Changed
@@ -116,6 +121,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
116
121
  - ASCII diagrams for tree rotation operations
117
122
  - MIT License (Copyright © 2026 Masahito Suzuki)
118
123
 
124
+ [0.2.0]: https://github.com/firelzrd/rbtree-ruby/releases/tag/v0.2.0
119
125
  [0.1.8]: https://github.com/firelzrd/rbtree-ruby/releases/tag/v0.1.8
120
126
  [0.1.7]: https://github.com/firelzrd/rbtree-ruby/releases/tag/v0.1.7
121
127
  [0.1.6]: https://github.com/firelzrd/rbtree-ruby/releases/tag/v0.1.6
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.8"
5
+ VERSION = "0.2.0"
6
6
  end
data/lib/rbtree.rb CHANGED
@@ -1461,9 +1461,10 @@ class MultiRBTree < RBTree
1461
1461
  [n.key, last ? n.value.last : n.value.first]
1462
1462
  end
1463
1463
 
1464
- def nearest(key)
1464
+ def nearest(key, last: false)
1465
1465
  n = find_nearest_node(key)
1466
- 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]
1467
1468
  end
1468
1469
 
1469
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.8
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: []