red-black-tree 0.1.4 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3e772062ad3ed9928eff044fa4e40bbd80dd0ab121a0c9cb2982969159bcf1ef
4
- data.tar.gz: ad53b47275b4c5ad04a80faf5e05a06e5e7576cb33f7d232e502c30b1a4455c8
3
+ metadata.gz: da41036d61ffc0739627740b631dbb00df76ee87a5db6145ad508569552703c3
4
+ data.tar.gz: 99172cd947f7714788dadd94068ff637bdfa510ae78367a4689a892dc4ad1a05
5
5
  SHA512:
6
- metadata.gz: 856164178d9887beec334f8a2fea1a51f60cf3f822a427a2a232847720a9c016250404e2af244962fe4033dbfaecfb447c3e746c3ebbe6861c77dab3ed6b3216
7
- data.tar.gz: c1a13b5313f3b31c9a0aab24e708e556ac9b707ea53ed539f7aaaa7fa6264eb17ca2205be6efdc1690277acb3d8ea09536590d1b5864e133fa9d649740d1fc51
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.3.5 (2024-09-03 revision ef084cc8f4) [arm64-darwin24]
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) 78.000 i/100ms
90
+ #=> Array (single sort) 100.000 i/100ms
91
91
  #=> Calculating -------------------------------------
92
- #=> RedBlackTree 5.4170.0%) i/s (184.61 ms/i) - 28.000 in 5.172532s
93
- #=> Array (gradual sort) 0.268 (± 0.0%) i/s (3.74 s/i) - 2.000 in 7.473005s
94
- #=> Array (single sort) 768.691 (± 2.2%) i/s (1.30 ms/i) - 3.900k in 5.076337s
92
+ #=> RedBlackTree 16.6846.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): 768.7 i/s
98
- #=> RedBlackTree: 5.4 i/s - 141.91x slower
99
- #=> Array (gradual sort): 0.3 i/s - 2872.03x slower
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.3.5 (2024-09-03 revision ef084cc8f4) [arm64-darwin24]
156
+ #=> ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +PRISM [arm64-darwin24]
157
157
  #=> Warming up --------------------------------------
158
- #=> RedBlackTree#search 1.000 i/100ms
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
- #=> 69.000 i/100ms
162
+ #=> 95.000 i/100ms
163
163
  #=> Array#bsearch (gradual sort)
164
164
  #=> 1.000 i/100ms
165
165
  #=> Array#bsearch (single sort)
166
- #=> 89.000 i/100ms
166
+ #=> 108.000 i/100ms
167
167
  #=> Calculating -------------------------------------
168
- #=> RedBlackTree#search 12.9260.0%) i/s (77.36 ms/i) - 65.000 in 5.030736s
168
+ #=> RedBlackTree#search 42.8504.7%) i/s (23.34 ms/i) - 216.000 in 5.049896s
169
169
  #=> Array#find (gradual sort)
170
- #=> 0.262 (± 0.0%) i/s (3.81 s/i) - 2.000 in 7.623953s
170
+ #=> 0.274 (± 0.0%) i/s (3.65 s/i) - 2.000 in 7.302412s
171
171
  #=> Array#find (single sort)
172
- #=> 690.6311.0%) i/s (1.45 ms/i) - 3.519k in 5.095823s
172
+ #=> 935.4922.7%) i/s (1.07 ms/i) - 4.750k in 5.081415s
173
173
  #=> Array#bsearch (gradual sort)
174
- #=> 0.267 (± 0.0%) i/s (3.75 s/i) - 2.000 in 7.492482s
174
+ #=> 0.275 (± 0.0%) i/s (3.63 s/i) - 2.000 in 7.269027s
175
175
  #=> Array#bsearch (single sort)
176
- #=> 895.4131.7%) i/s (1.12 ms/i) - 4.539k in 5.070590s
176
+ #=> 1.104k2.0%) i/s (905.52 μs/i) - 5.616k in 5.087395s
177
177
  #=>
178
178
  #=> Comparison:
179
- #=> Array#bsearch (single sort): 895.4 i/s
180
- #=> Array#find (single sort): 690.6 i/s - 1.30x slower
181
- #=> RedBlackTree#search: 12.9 i/s - 69.27x slower
182
- #=> Array#bsearch (gradual sort): 0.3 i/s - 3354.39x slower
183
- #=> Array#find (gradual sort): 0.3 i/s - 3412.57x slower
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
@@ -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.swap_data_with! successor
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
- return delete! successor
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
- node.swap_data_with! valid_child
158
- node.black!
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
- @root = node if is_root
174
+ original_node.validate_free!
161
175
 
162
- return delete! valid_child
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
@@ -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
- temp_parent = other_node.parent
163
- other_node.parent = self
164
- @parent = temp_parent
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
- temp_parent = other_node.parent
169
+ temp_node = other_node.parent
170
170
  other_node.parent = @parent
171
- @parent = temp_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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class RedBlackTree
4
- VERSION = "0.1.4"
4
+ VERSION = "0.1.6"
5
5
  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
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: 2024-10-27 00:00:00.000000000 Z
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.5.16
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: []