red-black-tree 0.1.4 → 0.1.6
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 +9 -0
- data/README.md +22 -22
- data/lib/red-black-tree.rb +51 -15
- data/lib/red_black_tree/node/left_right_element_referencers.rb +2 -2
- data/lib/red_black_tree/node.rb +28 -14
- data/lib/red_black_tree/version.rb +1 -1
- metadata +3 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: da41036d61ffc0739627740b631dbb00df76ee87a5db6145ad508569552703c3
|
4
|
+
data.tar.gz: 99172cd947f7714788dadd94068ff637bdfa510ae78367a4689a892dc4ad1a05
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 96e4b84d481b71cf8f3e45b728d19c1417f50c68ea9a9b8acdbd35a3514c8ab154df42ef7b3542ff0655e45c76a2f39b2a4a7ad6131a2c238fd7b126bddc29bd
|
7
|
+
data.tar.gz: 54a7743f84d5748e830dee7ed27c66f34c9517d4977b496c74cc6aa194b0fbef175f5ad7bd3d7420ce64f68298ff4bf529b9d1664966c94007db5fd1cc76d35d
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,14 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.1.6] - 2025-01-01
|
4
|
+
|
5
|
+
- Prefer node deletion over data swapping
|
6
|
+
|
7
|
+
## [0.1.5] - 2024-10-28
|
8
|
+
|
9
|
+
- Alias `RedBlackTree#search` as `RedBlackTree#find`
|
10
|
+
- Add `RedBlackTree#select`, aliased as `RedBlackTree#filter` and `RedBlackTree#find_all`
|
11
|
+
|
3
12
|
## [0.1.4] - 2024-10-27
|
4
13
|
|
5
14
|
- Fix incorrect `super` fallback in `RedBlackTree::DataDelegation#respond_to_missing?`
|
data/README.md
CHANGED
@@ -83,20 +83,20 @@ Benchmark.ips do |x|
|
|
83
83
|
x.compare!
|
84
84
|
end
|
85
85
|
|
86
|
-
#=> ruby 3.
|
86
|
+
#=> ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +PRISM [arm64-darwin24]
|
87
87
|
#=> Warming up --------------------------------------
|
88
88
|
#=> RedBlackTree 1.000 i/100ms
|
89
89
|
#=> Array (gradual sort) 1.000 i/100ms
|
90
|
-
#=> Array (single sort)
|
90
|
+
#=> Array (single sort) 100.000 i/100ms
|
91
91
|
#=> Calculating -------------------------------------
|
92
|
-
#=> RedBlackTree
|
93
|
-
#=> Array (gradual sort) 0.
|
94
|
-
#=> Array (single sort)
|
92
|
+
#=> RedBlackTree 16.684 (± 6.0%) i/s (59.94 ms/i) - 84.000 in 5.053688s
|
93
|
+
#=> Array (gradual sort) 0.270 (± 0.0%) i/s (3.71 s/i) - 2.000 in 7.418650s
|
94
|
+
#=> Array (single sort) 1.006k (± 2.4%) i/s (994.28 μs/i) - 5.100k in 5.073834s
|
95
95
|
#=>
|
96
96
|
#=> Comparison:
|
97
|
-
#=> Array (single sort):
|
98
|
-
#=> RedBlackTree:
|
99
|
-
#=> Array (gradual sort): 0.3 i/s -
|
97
|
+
#=> Array (single sort): 1005.8 i/s
|
98
|
+
#=> RedBlackTree: 16.7 i/s - 60.28x slower
|
99
|
+
#=> Array (gradual sort): 0.3 i/s - 3729.44x slower
|
100
100
|
```
|
101
101
|
|
102
102
|
### Sort and search 10,000 elements
|
@@ -153,34 +153,34 @@ Benchmark.ips do |x|
|
|
153
153
|
x.compare!
|
154
154
|
end
|
155
155
|
|
156
|
-
#=> ruby 3.
|
156
|
+
#=> ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +PRISM [arm64-darwin24]
|
157
157
|
#=> Warming up --------------------------------------
|
158
|
-
#=> RedBlackTree#search
|
158
|
+
#=> RedBlackTree#search 3.000 i/100ms
|
159
159
|
#=> Array#find (gradual sort)
|
160
160
|
#=> 1.000 i/100ms
|
161
161
|
#=> Array#find (single sort)
|
162
|
-
#=>
|
162
|
+
#=> 95.000 i/100ms
|
163
163
|
#=> Array#bsearch (gradual sort)
|
164
164
|
#=> 1.000 i/100ms
|
165
165
|
#=> Array#bsearch (single sort)
|
166
|
-
#=>
|
166
|
+
#=> 108.000 i/100ms
|
167
167
|
#=> Calculating -------------------------------------
|
168
|
-
#=> RedBlackTree#search
|
168
|
+
#=> RedBlackTree#search 42.850 (± 4.7%) i/s (23.34 ms/i) - 216.000 in 5.049896s
|
169
169
|
#=> Array#find (gradual sort)
|
170
|
-
#=> 0.
|
170
|
+
#=> 0.274 (± 0.0%) i/s (3.65 s/i) - 2.000 in 7.302412s
|
171
171
|
#=> Array#find (single sort)
|
172
|
-
#=>
|
172
|
+
#=> 935.492 (± 2.7%) i/s (1.07 ms/i) - 4.750k in 5.081415s
|
173
173
|
#=> Array#bsearch (gradual sort)
|
174
|
-
#=> 0.
|
174
|
+
#=> 0.275 (± 0.0%) i/s (3.63 s/i) - 2.000 in 7.269027s
|
175
175
|
#=> Array#bsearch (single sort)
|
176
|
-
#=>
|
176
|
+
#=> 1.104k (± 2.0%) i/s (905.52 μs/i) - 5.616k in 5.087395s
|
177
177
|
#=>
|
178
178
|
#=> Comparison:
|
179
|
-
#=>
|
180
|
-
#=>
|
181
|
-
#=>
|
182
|
-
#=> Array#bsearch (gradual sort):
|
183
|
-
#=>
|
179
|
+
#=> Array#bsearch (single sort): 1104.3 i/s
|
180
|
+
#=> Array#find (single sort): 935.5 i/s - 1.18x slower
|
181
|
+
#=> RedBlackTree#search: 42.9 i/s - 25.77x slower
|
182
|
+
#=> Array#bsearch (gradual sort): 0.3 i/s - 4013.67x slower
|
183
|
+
#=> Array#find (gradual sort): 0.3 i/s - 4031.85x slower
|
184
184
|
```
|
185
185
|
|
186
186
|
## WIP Features
|
data/lib/red-black-tree.rb
CHANGED
@@ -145,21 +145,38 @@ class RedBlackTree
|
|
145
145
|
original_node = node
|
146
146
|
|
147
147
|
if node.children_are_valid?
|
148
|
+
is_root = is_root? node
|
149
|
+
|
148
150
|
successor = node.left
|
149
151
|
successor = successor.left until successor.left.leaf?
|
150
|
-
node.
|
152
|
+
node.swap_colour_with! successor
|
153
|
+
node.swap_position_with! successor
|
154
|
+
node.swap_position_with! LeafNode.new
|
155
|
+
|
156
|
+
@root = successor if is_root
|
157
|
+
|
158
|
+
original_node.validate_free!
|
151
159
|
|
152
|
-
|
160
|
+
decrement_size!
|
161
|
+
update_left_most_node!
|
162
|
+
|
163
|
+
return self
|
153
164
|
elsif node.single_child_is_valid?
|
154
165
|
is_root = is_root? node
|
155
166
|
|
156
167
|
valid_child = node.children.find(&:valid?)
|
157
|
-
|
158
|
-
node.
|
168
|
+
valid_child.black!
|
169
|
+
node.swap_position_with! valid_child
|
170
|
+
node.swap_position_with! LeafNode.new
|
171
|
+
|
172
|
+
@root = valid_child if is_root
|
159
173
|
|
160
|
-
|
174
|
+
original_node.validate_free!
|
161
175
|
|
162
|
-
|
176
|
+
decrement_size!
|
177
|
+
update_left_most_node!
|
178
|
+
|
179
|
+
return self
|
163
180
|
elsif node.children_are_leaves?
|
164
181
|
if is_root? node
|
165
182
|
@root = nil
|
@@ -224,7 +241,7 @@ class RedBlackTree
|
|
224
241
|
# @return [RedBlackTree::Node, nil] the matching node
|
225
242
|
def search data = nil, &block
|
226
243
|
if block_given?
|
227
|
-
raise ArgumentError, "provide either data or block, not both" if data
|
244
|
+
raise ArgumentError, "provide either data or block, not both for search" if data
|
228
245
|
|
229
246
|
_search_by_block block, @root
|
230
247
|
else
|
@@ -233,6 +250,15 @@ class RedBlackTree
|
|
233
250
|
_search_by_data data, @root
|
234
251
|
end
|
235
252
|
end
|
253
|
+
alias_method :find, :search
|
254
|
+
|
255
|
+
def select &block
|
256
|
+
raise ArgumentError, "block must be provided for select" unless block
|
257
|
+
|
258
|
+
_select_by_block block, @root
|
259
|
+
end
|
260
|
+
alias_method :filter, :select
|
261
|
+
alias_method :find_all, :select
|
236
262
|
|
237
263
|
# Returns true if there is a node which matches the given data/value, and false if there is not.
|
238
264
|
#
|
@@ -327,14 +353,6 @@ class RedBlackTree
|
|
327
353
|
opp_direction_child
|
328
354
|
end
|
329
355
|
|
330
|
-
def _search_by_block block, node
|
331
|
-
traverse node do |current|
|
332
|
-
next if current.leaf?
|
333
|
-
|
334
|
-
return current if block.call current
|
335
|
-
end
|
336
|
-
end
|
337
|
-
|
338
356
|
def _search_by_data data, node
|
339
357
|
return if node.nil? || node.leaf?
|
340
358
|
return node if data == node.data
|
@@ -347,6 +365,24 @@ class RedBlackTree
|
|
347
365
|
end
|
348
366
|
end
|
349
367
|
|
368
|
+
def _search_by_block block, node
|
369
|
+
traverse node do |current|
|
370
|
+
next if current.leaf?
|
371
|
+
|
372
|
+
return current if block.call current
|
373
|
+
end
|
374
|
+
end
|
375
|
+
|
376
|
+
def _select_by_block block, node
|
377
|
+
[].tap do |result|
|
378
|
+
traverse node do |current|
|
379
|
+
next if current.leaf?
|
380
|
+
|
381
|
+
result << current if block.call current
|
382
|
+
end
|
383
|
+
end
|
384
|
+
end
|
385
|
+
|
350
386
|
def is_root? node
|
351
387
|
node && @root && node.object_id == @root.object_id
|
352
388
|
end
|
@@ -7,7 +7,7 @@ class RedBlackTree
|
|
7
7
|
case direction
|
8
8
|
when Node::LEFT then @left
|
9
9
|
when Node::RIGHT then @right
|
10
|
-
else raise ArgumentError, "Direction must be one of #{Implementation::DIRECTIONS}"
|
10
|
+
else raise ArgumentError, "Direction must be one of #{Implementation::DIRECTIONS}, got #{direction}"
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
@@ -15,7 +15,7 @@ class RedBlackTree
|
|
15
15
|
case direction
|
16
16
|
when Node::LEFT then @left = node
|
17
17
|
when Node::RIGHT then @right = node
|
18
|
-
else raise ArgumentError, "Direction must be one of #{Implementation::DIRECTIONS}"
|
18
|
+
else raise ArgumentError, "Direction must be one of #{Implementation::DIRECTIONS}, got #{direction}"
|
19
19
|
end
|
20
20
|
end
|
21
21
|
end
|
data/lib/red_black_tree/node.rb
CHANGED
@@ -125,12 +125,6 @@ class RedBlackTree
|
|
125
125
|
raise StructuralError, "Node is still chained to #{anchors.join(", ")}"
|
126
126
|
end
|
127
127
|
|
128
|
-
def swap_data_with! other_node
|
129
|
-
temp_data = @data
|
130
|
-
@data = other_node.data
|
131
|
-
other_node.data = temp_data
|
132
|
-
end
|
133
|
-
|
134
128
|
def swap_colour_with! other_node
|
135
129
|
temp_colour = @colour
|
136
130
|
|
@@ -148,27 +142,47 @@ class RedBlackTree
|
|
148
142
|
def swap_position_with! other_node
|
149
143
|
self_position = position
|
150
144
|
other_position = other_node.position
|
145
|
+
opp_other_position = opposite_direction other_position if other_position
|
151
146
|
|
152
147
|
if other_node.parent.object_id == self.object_id
|
153
148
|
self[other_position] = other_node[other_position]
|
154
149
|
other_node[other_position] = self
|
155
150
|
|
151
|
+
self[other_position].parent = self
|
156
152
|
other_node.parent = @parent
|
153
|
+
|
154
|
+
@parent[self_position] = other_node if self_position
|
157
155
|
@parent = other_node
|
158
|
-
elsif other_node.object_id == @parent.object_id
|
159
|
-
other_node[self_position] = self[self_position]
|
160
|
-
self[self_position] = other_node
|
161
156
|
|
162
|
-
|
163
|
-
|
164
|
-
|
157
|
+
temp_node = self[opp_other_position]
|
158
|
+
self[opp_other_position] = other_node[opp_other_position]
|
159
|
+
other_node[opp_other_position] = temp_node
|
160
|
+
|
161
|
+
self[opp_other_position].parent = self
|
162
|
+
other_node[opp_other_position].parent = other_node
|
163
|
+
elsif other_node.object_id == @parent.object_id
|
164
|
+
other_node.swap_position_with! self
|
165
165
|
else
|
166
166
|
other_node.parent[other_position] = self if other_node.parent
|
167
167
|
@parent[self_position] = other_node if @parent
|
168
168
|
|
169
|
-
|
169
|
+
temp_node = other_node.parent
|
170
170
|
other_node.parent = @parent
|
171
|
-
@parent =
|
171
|
+
@parent = temp_node
|
172
|
+
|
173
|
+
temp_node = other_node.left
|
174
|
+
other_node.left = @left
|
175
|
+
@left = temp_node
|
176
|
+
|
177
|
+
@left.parent = self if @left
|
178
|
+
other_node.left.parent = other_node if other_node.left
|
179
|
+
|
180
|
+
temp_node = other_node.right
|
181
|
+
other_node.right = @right
|
182
|
+
@right = temp_node
|
183
|
+
|
184
|
+
@right.parent = self if @right
|
185
|
+
other_node.right.parent = other_node if other_node.right
|
172
186
|
end
|
173
187
|
end
|
174
188
|
end
|
metadata
CHANGED
@@ -1,16 +1,14 @@
|
|
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.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joshua Young
|
8
|
-
autorequire:
|
9
8
|
bindir: bin
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 2025-01-01 00:00:00.000000000 Z
|
12
11
|
dependencies: []
|
13
|
-
description:
|
14
12
|
email:
|
15
13
|
- djry1999@gmail.com
|
16
14
|
executables: []
|
@@ -37,7 +35,6 @@ metadata:
|
|
37
35
|
documentation_uri: https://joshuay03.github.io/red-black-tree/
|
38
36
|
source_code_uri: https://github.com/joshuay03/red-black-tree
|
39
37
|
changelog_uri: https://github.com/joshuay03/red-black-tree/blob/main/CHANGELOG.md
|
40
|
-
post_install_message:
|
41
38
|
rdoc_options: []
|
42
39
|
require_paths:
|
43
40
|
- lib
|
@@ -52,8 +49,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
52
49
|
- !ruby/object:Gem::Version
|
53
50
|
version: '0'
|
54
51
|
requirements: []
|
55
|
-
rubygems_version: 3.
|
56
|
-
signing_key:
|
52
|
+
rubygems_version: 3.6.2
|
57
53
|
specification_version: 4
|
58
54
|
summary: Red-Black Tree Data Structure for Ruby
|
59
55
|
test_files: []
|