red-black-tree 0.1.8 → 0.1.10
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 +10 -0
- data/README.md +25 -25
- data/lib/red-black-tree.rb +28 -12
- data/lib/red_black_tree/node.rb +1 -1
- data/lib/red_black_tree/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ef532dd5b5da89ad3dbf780bba52824ecdece998306dc89d4742ddd7b9444a1b
|
|
4
|
+
data.tar.gz: dee8cd6cb0ebf9b837519d9131790590e6fcab86c5fe45af0d28cb603d53f224
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 75b0530cb685fb3cfcd1fa8435a8329e97df9fbd49e5e7063b5de0c34cbef24c453dc5d22481c8ba4cafe475f48ea3ccafa37788ef92b066c667882ce860130c
|
|
7
|
+
data.tar.gz: 8fdf009768bfb1551f2f4954ddab323c12b1d76d438c0be8b2bbb4ffe10816de58513e2642649ad78b25b1ea931a03a29a82b3d2df6a3dfeae70997158fe9183
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.1.10] - 2026-05-17
|
|
4
|
+
|
|
5
|
+
- Fix `RedBlackTree#delete!` orphaning predecessor's child when deleting a node with two valid children
|
|
6
|
+
|
|
7
|
+
## [0.1.9] - 2026-05-10
|
|
8
|
+
|
|
9
|
+
- Add `Enumerable` to `RedBlackTree`
|
|
10
|
+
- Fix `RedBlackTree#clear!` not detaching nodes
|
|
11
|
+
- Fix `LeafNodeComparable` being prepended to `LeafNode`
|
|
12
|
+
|
|
3
13
|
## [0.1.8] - 2025-07-26
|
|
4
14
|
|
|
5
15
|
- Refactor to slim down and de-duplicate some methods
|
data/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# RedBlackTree
|
|
2
2
|
|
|
3
3
|

|
|
4
|
-

|
|
5
5
|
|
|
6
6
|
[Red-black tree](https://en.wikipedia.org/wiki/Red%E2%80%93black_tree) data structure for Ruby.
|
|
7
7
|
|
|
@@ -86,20 +86,20 @@ Benchmark.ips do |x|
|
|
|
86
86
|
x.compare!
|
|
87
87
|
end
|
|
88
88
|
|
|
89
|
-
#=> ruby
|
|
89
|
+
#=> ruby 4.0.3 (2026-04-21 revision 85ddef263a) +YJIT +PRISM [arm64-darwin23]
|
|
90
90
|
#=> Warming up --------------------------------------
|
|
91
91
|
#=> RedBlackTree 1.000 i/100ms
|
|
92
92
|
#=> Array (gradual sort) 1.000 i/100ms
|
|
93
|
-
#=> Array (single sort)
|
|
93
|
+
#=> Array (single sort) 81.000 i/100ms
|
|
94
94
|
#=> Calculating -------------------------------------
|
|
95
|
-
#=> RedBlackTree
|
|
96
|
-
#=> Array (gradual sort) 0.
|
|
97
|
-
#=> Array (single sort)
|
|
98
|
-
#=>
|
|
95
|
+
#=> RedBlackTree 12.170 (± 8.2%) i/s (82.17 ms/i) - 61.000 in 5.023274s
|
|
96
|
+
#=> Array (gradual sort) 0.208 (± 0.0%) i/s (4.82 s/i) - 2.000 in 9.632733s
|
|
97
|
+
#=> Array (single sort) 815.762 (± 1.2%) i/s (1.23 ms/i) - 4.131k in 5.064788s
|
|
98
|
+
#=>
|
|
99
99
|
#=> Comparison:
|
|
100
|
-
#=> Array (single sort):
|
|
101
|
-
#=> RedBlackTree:
|
|
102
|
-
#=> Array (gradual sort): 0.
|
|
100
|
+
#=> Array (single sort): 815.8 i/s
|
|
101
|
+
#=> RedBlackTree: 12.2 i/s - 67.03x slower
|
|
102
|
+
#=> Array (gradual sort): 0.2 i/s - 3928.64x slower
|
|
103
103
|
```
|
|
104
104
|
|
|
105
105
|
### Sort and search 10,000 elements
|
|
@@ -122,7 +122,7 @@ Benchmark.ips do |x|
|
|
|
122
122
|
x.report("RedBlackTree#search") do
|
|
123
123
|
tree = RedBlackTree.new
|
|
124
124
|
sample_data.each { |work| tree << WorkNode.new(work); }
|
|
125
|
-
raise unless tree.search search_sample
|
|
125
|
+
raise unless tree.search { |node| node.data == search_sample }
|
|
126
126
|
end
|
|
127
127
|
|
|
128
128
|
# 1:1 comparison
|
|
@@ -156,34 +156,34 @@ Benchmark.ips do |x|
|
|
|
156
156
|
x.compare!
|
|
157
157
|
end
|
|
158
158
|
|
|
159
|
-
#=> ruby
|
|
159
|
+
#=> ruby 4.0.3 (2026-04-21 revision 85ddef263a) +YJIT +PRISM [arm64-darwin23]
|
|
160
160
|
#=> Warming up --------------------------------------
|
|
161
161
|
#=> RedBlackTree#search 3.000 i/100ms
|
|
162
162
|
#=> Array#find (gradual sort)
|
|
163
163
|
#=> 1.000 i/100ms
|
|
164
164
|
#=> Array#find (single sort)
|
|
165
|
-
#=>
|
|
165
|
+
#=> 79.000 i/100ms
|
|
166
166
|
#=> Array#bsearch (gradual sort)
|
|
167
167
|
#=> 1.000 i/100ms
|
|
168
168
|
#=> Array#bsearch (single sort)
|
|
169
|
-
#=>
|
|
169
|
+
#=> 87.000 i/100ms
|
|
170
170
|
#=> Calculating -------------------------------------
|
|
171
|
-
#=> RedBlackTree#search
|
|
171
|
+
#=> RedBlackTree#search 32.188 (± 6.2%) i/s (31.07 ms/i) - 162.000 in 5.051229s
|
|
172
172
|
#=> Array#find (gradual sort)
|
|
173
|
-
#=> 0.
|
|
173
|
+
#=> 0.207 (± 0.0%) i/s (4.83 s/i) - 2.000 in 9.651532s
|
|
174
174
|
#=> Array#find (single sort)
|
|
175
|
-
#=>
|
|
175
|
+
#=> 809.310 (± 3.8%) i/s (1.24 ms/i) - 4.108k in 5.084020s
|
|
176
176
|
#=> Array#bsearch (gradual sort)
|
|
177
|
-
#=> 0.
|
|
177
|
+
#=> 0.205 (± 0.0%) i/s (4.88 s/i) - 2.000 in 9.753754s
|
|
178
178
|
#=> Array#bsearch (single sort)
|
|
179
|
-
#=>
|
|
180
|
-
#=>
|
|
179
|
+
#=> 857.497 (± 1.0%) i/s (1.17 ms/i) - 4.350k in 5.073414s
|
|
180
|
+
#=>
|
|
181
181
|
#=> Comparison:
|
|
182
|
-
#=>
|
|
183
|
-
#=>
|
|
184
|
-
#=>
|
|
185
|
-
#=> Array#
|
|
186
|
-
#=>
|
|
182
|
+
#=> Array#bsearch (single sort): 857.5 i/s
|
|
183
|
+
#=> Array#find (single sort): 809.3 i/s - 1.06x slower
|
|
184
|
+
#=> RedBlackTree#search: 32.2 i/s - 26.64x slower
|
|
185
|
+
#=> Array#find (gradual sort): 0.2 i/s - 4138.00x slower
|
|
186
|
+
#=> Array#bsearch (gradual sort): 0.2 i/s - 4181.79x slower
|
|
187
187
|
```
|
|
188
188
|
|
|
189
189
|
## WIP Features
|
data/lib/red-black-tree.rb
CHANGED
|
@@ -6,6 +6,7 @@ require_relative "red_black_tree/node/leaf_node"
|
|
|
6
6
|
|
|
7
7
|
class RedBlackTree
|
|
8
8
|
include Utils
|
|
9
|
+
include Enumerable
|
|
9
10
|
|
|
10
11
|
# @return [Integer] the number of valid/non-leaf nodes
|
|
11
12
|
attr_reader :size
|
|
@@ -134,7 +135,9 @@ class RedBlackTree
|
|
|
134
135
|
|
|
135
136
|
if node.children_are_valid?
|
|
136
137
|
delete_node_with_two_children! node
|
|
137
|
-
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
if node.single_child_is_valid?
|
|
138
141
|
delete_node_with_one_child! node
|
|
139
142
|
elsif node.children_are_leaves?
|
|
140
143
|
delete_leaf_node! node, original_node
|
|
@@ -153,6 +156,11 @@ class RedBlackTree
|
|
|
153
156
|
#
|
|
154
157
|
# @return [RedBlackTree] self
|
|
155
158
|
def clear!
|
|
159
|
+
traverse_post_order do |node|
|
|
160
|
+
node.tree = nil
|
|
161
|
+
node.colour = node.parent = node.left = node.right = nil
|
|
162
|
+
end
|
|
163
|
+
|
|
156
164
|
@root = nil
|
|
157
165
|
@size = 0
|
|
158
166
|
@left_most_node = nil
|
|
@@ -179,7 +187,7 @@ class RedBlackTree
|
|
|
179
187
|
alias_method :find, :search
|
|
180
188
|
|
|
181
189
|
def select &block
|
|
182
|
-
raise ArgumentError, "block must be provided for select" unless
|
|
190
|
+
raise ArgumentError, "block must be provided for select" unless block_given?
|
|
183
191
|
|
|
184
192
|
_select_by_block block, @root
|
|
185
193
|
end
|
|
@@ -193,6 +201,17 @@ class RedBlackTree
|
|
|
193
201
|
!search(data).nil?
|
|
194
202
|
end
|
|
195
203
|
|
|
204
|
+
# Traverses the tree in in-order and yields each node.
|
|
205
|
+
# When called without a block, returns an {Enumerator}.
|
|
206
|
+
#
|
|
207
|
+
# @yield [RedBlackTree::Node] the block to be executed for each node
|
|
208
|
+
# @return [void, Enumerator]
|
|
209
|
+
def each &block
|
|
210
|
+
return enum_for(:each) unless block_given?
|
|
211
|
+
|
|
212
|
+
traverse_in_order(&block)
|
|
213
|
+
end
|
|
214
|
+
|
|
196
215
|
# Traverses the tree in pre-order and yields each node.
|
|
197
216
|
#
|
|
198
217
|
# @param node [RedBlackTree::Node] the node to start the traversal from
|
|
@@ -243,11 +262,9 @@ class RedBlackTree
|
|
|
243
262
|
queue = [@root]
|
|
244
263
|
until queue.empty?
|
|
245
264
|
node = queue.shift
|
|
246
|
-
next if node.nil? || node.leaf?
|
|
247
|
-
|
|
248
265
|
block.call node
|
|
249
|
-
queue << node.left
|
|
250
|
-
queue << node.right
|
|
266
|
+
queue << node.left unless node.left.leaf?
|
|
267
|
+
queue << node.right unless node.right.leaf?
|
|
251
268
|
end
|
|
252
269
|
end
|
|
253
270
|
|
|
@@ -329,13 +346,12 @@ class RedBlackTree
|
|
|
329
346
|
def delete_node_with_two_children! node
|
|
330
347
|
is_root = is_root? node
|
|
331
348
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
node.swap_colour_with!
|
|
335
|
-
node.swap_position_with!
|
|
336
|
-
node.swap_position_with! LeafNode.new
|
|
349
|
+
predecessor = node.left
|
|
350
|
+
predecessor = predecessor.right until predecessor.right.leaf?
|
|
351
|
+
node.swap_colour_with! predecessor
|
|
352
|
+
node.swap_position_with! predecessor
|
|
337
353
|
|
|
338
|
-
@root =
|
|
354
|
+
@root = predecessor if is_root
|
|
339
355
|
end
|
|
340
356
|
|
|
341
357
|
def delete_node_with_one_child! node
|
data/lib/red_black_tree/node.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: red-black-tree
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.10
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Joshua Young
|
|
@@ -49,7 +49,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
49
49
|
- !ruby/object:Gem::Version
|
|
50
50
|
version: '0'
|
|
51
51
|
requirements: []
|
|
52
|
-
rubygems_version:
|
|
52
|
+
rubygems_version: 4.0.10
|
|
53
53
|
specification_version: 4
|
|
54
54
|
summary: Red-Black Tree Data Structure for Ruby
|
|
55
55
|
test_files: []
|