red-black-tree 0.1.7 → 0.1.8
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 +4 -0
- data/README.md +3 -0
- data/lib/red-black-tree.rb +129 -110
- data/lib/red_black_tree/node/left_right_element_referencers.rb +9 -2
- data/lib/red_black_tree/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e7cc7e3138c1b0ceea2d6b5a2f91620323f75ebe346288bc69761d77d95eb5c4
|
4
|
+
data.tar.gz: 057d9d283d5312f6c5f8e155e3c039c342d036b779d115738c7afbc57ca419f4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 61f4a9a44d3949b3c2072de4fbca1507cf78306adc32dae8bad26ec5a71171ae952cb81effddf41990a8e2b6dc0e06d39a121389e5bc4c3438eca981dc2a0b59
|
7
|
+
data.tar.gz: c9bced3565a3ec9439c1c08dca09676d1c3966cb18a97507c1f815e938b73419f9f3bce0e4d13d06e97dc59a92f845a3b9b4f094841aa900bde3b004959baeca
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
# RedBlackTree
|
2
2
|
|
3
|
+

|
4
|
+

|
5
|
+
|
3
6
|
[Red-black tree](https://en.wikipedia.org/wiki/Red%E2%80%93black_tree) data structure for Ruby.
|
4
7
|
|
5
8
|
## Installation
|
data/lib/red-black-tree.rb
CHANGED
@@ -106,27 +106,7 @@ class RedBlackTree
|
|
106
106
|
node.parent = target_parent
|
107
107
|
node.red!
|
108
108
|
|
109
|
-
|
110
|
-
if node.parent.sibling && node.parent.sibling.red?
|
111
|
-
node.parent.black!
|
112
|
-
node.parent.sibling.black!
|
113
|
-
node.parent.parent.red!
|
114
|
-
node = node.parent.parent
|
115
|
-
else
|
116
|
-
opp_direction = node.opposite_position
|
117
|
-
if node.parent.position == opp_direction
|
118
|
-
rotate_sub_tree! node.parent, opp_direction
|
119
|
-
node = node[opp_direction]
|
120
|
-
end
|
121
|
-
|
122
|
-
opp_direction = node.opposite_position
|
123
|
-
rotate_sub_tree! node.parent.parent, opp_direction
|
124
|
-
node.parent.black!
|
125
|
-
node.parent[opp_direction].red!
|
126
|
-
end
|
127
|
-
|
128
|
-
@root.black!
|
129
|
-
end
|
109
|
+
rebalance_after_insertion! node
|
130
110
|
end
|
131
111
|
|
132
112
|
node.validate! @root == node
|
@@ -153,71 +133,11 @@ class RedBlackTree
|
|
153
133
|
original_node = node
|
154
134
|
|
155
135
|
if node.children_are_valid?
|
156
|
-
|
157
|
-
|
158
|
-
successor = node.left
|
159
|
-
successor = successor.left until successor.left.leaf?
|
160
|
-
node.swap_colour_with! successor
|
161
|
-
node.swap_position_with! successor
|
162
|
-
node.swap_position_with! LeafNode.new
|
163
|
-
|
164
|
-
@root = successor if is_root
|
136
|
+
delete_node_with_two_children! node
|
165
137
|
elsif node.single_child_is_valid?
|
166
|
-
|
167
|
-
|
168
|
-
valid_child = node.children.find(&:valid?)
|
169
|
-
valid_child.black!
|
170
|
-
node.swap_position_with! valid_child
|
171
|
-
node.swap_position_with! LeafNode.new
|
172
|
-
|
173
|
-
@root = valid_child if is_root
|
138
|
+
delete_node_with_one_child! node
|
174
139
|
elsif node.children_are_leaves?
|
175
|
-
|
176
|
-
@root = nil
|
177
|
-
elsif node.red?
|
178
|
-
node.swap_position_with! LeafNode.new
|
179
|
-
else
|
180
|
-
loop do
|
181
|
-
if node.sibling && node.sibling.valid? && node.sibling.red?
|
182
|
-
node.parent.red!
|
183
|
-
node.sibling.black!
|
184
|
-
rotate_sub_tree! node.parent, node.position
|
185
|
-
end
|
186
|
-
|
187
|
-
if node.close_nephew && node.close_nephew.valid? && node.close_nephew.red?
|
188
|
-
node.sibling.red! unless node.sibling.leaf?
|
189
|
-
node.close_nephew.black!
|
190
|
-
rotate_sub_tree! node.sibling, node.opposite_position
|
191
|
-
end
|
192
|
-
|
193
|
-
if node.distant_nephew && node.distant_nephew.valid? && node.distant_nephew.red?
|
194
|
-
case node.parent.colour
|
195
|
-
when Node::RED then node.sibling.red!
|
196
|
-
when Node::BLACK then node.sibling.black!
|
197
|
-
end
|
198
|
-
node.parent.black!
|
199
|
-
node.distant_nephew.black!
|
200
|
-
rotate_sub_tree! node.parent, node.position
|
201
|
-
|
202
|
-
break
|
203
|
-
end
|
204
|
-
|
205
|
-
if node.parent && node.parent.red?
|
206
|
-
node.sibling.red! unless node.sibling.leaf?
|
207
|
-
node.parent.black!
|
208
|
-
|
209
|
-
break
|
210
|
-
end
|
211
|
-
|
212
|
-
if node.sibling && !node.sibling.leaf?
|
213
|
-
node.sibling.red!
|
214
|
-
end
|
215
|
-
|
216
|
-
break unless node = node.parent
|
217
|
-
end
|
218
|
-
|
219
|
-
original_node.swap_position_with! LeafNode.new
|
220
|
-
end
|
140
|
+
delete_leaf_node! node, original_node
|
221
141
|
end
|
222
142
|
|
223
143
|
original_node.tree = nil
|
@@ -270,7 +190,7 @@ class RedBlackTree
|
|
270
190
|
#
|
271
191
|
# @return [true, false]
|
272
192
|
def include? data
|
273
|
-
|
193
|
+
!search(data).nil?
|
274
194
|
end
|
275
195
|
|
276
196
|
# Traverses the tree in pre-order and yields each node.
|
@@ -333,6 +253,29 @@ class RedBlackTree
|
|
333
253
|
|
334
254
|
private
|
335
255
|
|
256
|
+
def is_root? node
|
257
|
+
node && @root && node.object_id == @root.object_id
|
258
|
+
end
|
259
|
+
|
260
|
+
def increment_size!
|
261
|
+
@size += 1
|
262
|
+
end
|
263
|
+
|
264
|
+
def decrement_size!
|
265
|
+
@size -= 1
|
266
|
+
end
|
267
|
+
|
268
|
+
def update_left_most_node!
|
269
|
+
unless @root
|
270
|
+
@left_most_node = nil
|
271
|
+
return
|
272
|
+
end
|
273
|
+
|
274
|
+
current = @root
|
275
|
+
current = current.left until current.left.leaf?
|
276
|
+
@left_most_node = current
|
277
|
+
end
|
278
|
+
|
336
279
|
# Rotates a (sub-)tree starting from the given node in the given direction.
|
337
280
|
#
|
338
281
|
# @param node [RedBlackTree::Node] the root node of the sub-tree
|
@@ -359,12 +302,111 @@ class RedBlackTree
|
|
359
302
|
opp_direction_child
|
360
303
|
end
|
361
304
|
|
305
|
+
def rebalance_after_insertion! node
|
306
|
+
while node.parent && node.parent.red? do
|
307
|
+
if node.parent.sibling && node.parent.sibling.red?
|
308
|
+
node.parent.black!
|
309
|
+
node.parent.sibling.black!
|
310
|
+
node.parent.parent.red!
|
311
|
+
node = node.parent.parent
|
312
|
+
else
|
313
|
+
opp_direction = node.opposite_position
|
314
|
+
if node.parent.position == opp_direction
|
315
|
+
rotate_sub_tree! node.parent, opp_direction
|
316
|
+
node = node[opp_direction]
|
317
|
+
end
|
318
|
+
|
319
|
+
opp_direction = node.opposite_position
|
320
|
+
rotate_sub_tree! node.parent.parent, opp_direction
|
321
|
+
node.parent.black!
|
322
|
+
node.parent[opp_direction].red!
|
323
|
+
end
|
324
|
+
|
325
|
+
@root.black!
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
def delete_node_with_two_children! node
|
330
|
+
is_root = is_root? node
|
331
|
+
|
332
|
+
successor = node.left
|
333
|
+
successor = successor.right until successor.right.leaf?
|
334
|
+
node.swap_colour_with! successor
|
335
|
+
node.swap_position_with! successor
|
336
|
+
node.swap_position_with! LeafNode.new
|
337
|
+
|
338
|
+
@root = successor if is_root
|
339
|
+
end
|
340
|
+
|
341
|
+
def delete_node_with_one_child! node
|
342
|
+
is_root = is_root? node
|
343
|
+
|
344
|
+
valid_child = node.children.find(&:valid?)
|
345
|
+
valid_child.black!
|
346
|
+
node.swap_position_with! valid_child
|
347
|
+
node.swap_position_with! LeafNode.new
|
348
|
+
|
349
|
+
@root = valid_child if is_root
|
350
|
+
end
|
351
|
+
|
352
|
+
def delete_leaf_node! node, original_node
|
353
|
+
if is_root? node
|
354
|
+
@root = nil
|
355
|
+
elsif node.red?
|
356
|
+
node.swap_position_with! LeafNode.new
|
357
|
+
else
|
358
|
+
rebalance_after_deletion! node
|
359
|
+
original_node.swap_position_with! LeafNode.new
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
def rebalance_after_deletion! node
|
364
|
+
loop do
|
365
|
+
if node.sibling && node.sibling.valid? && node.sibling.red?
|
366
|
+
node.parent.red!
|
367
|
+
node.sibling.black!
|
368
|
+
rotate_sub_tree! node.parent, node.position
|
369
|
+
end
|
370
|
+
|
371
|
+
if node.close_nephew && node.close_nephew.valid? && node.close_nephew.red?
|
372
|
+
node.sibling.red! unless node.sibling.leaf?
|
373
|
+
node.close_nephew.black!
|
374
|
+
rotate_sub_tree! node.sibling, node.opposite_position
|
375
|
+
end
|
376
|
+
|
377
|
+
if node.distant_nephew && node.distant_nephew.valid? && node.distant_nephew.red?
|
378
|
+
case node.parent.colour
|
379
|
+
when Node::RED then node.sibling.red!
|
380
|
+
when Node::BLACK then node.sibling.black!
|
381
|
+
end
|
382
|
+
node.parent.black!
|
383
|
+
node.distant_nephew.black!
|
384
|
+
rotate_sub_tree! node.parent, node.position
|
385
|
+
|
386
|
+
break
|
387
|
+
end
|
388
|
+
|
389
|
+
if node.parent && node.parent.red?
|
390
|
+
node.sibling.red! unless node.sibling.leaf?
|
391
|
+
node.parent.black!
|
392
|
+
|
393
|
+
break
|
394
|
+
end
|
395
|
+
|
396
|
+
if node.sibling && !node.sibling.leaf?
|
397
|
+
node.sibling.red!
|
398
|
+
end
|
399
|
+
|
400
|
+
break unless node = node.parent
|
401
|
+
end
|
402
|
+
end
|
403
|
+
|
362
404
|
def _search_by_data data, node
|
363
405
|
return if node.nil? || node.leaf?
|
364
406
|
return node if data == node.data
|
365
407
|
|
366
|
-
|
367
|
-
if
|
408
|
+
comparison = data <=> node.data
|
409
|
+
if comparison && comparison >= 0
|
368
410
|
_search_by_data data, node.right
|
369
411
|
else
|
370
412
|
_search_by_data data, node.left
|
@@ -388,27 +430,4 @@ class RedBlackTree
|
|
388
430
|
end
|
389
431
|
end
|
390
432
|
end
|
391
|
-
|
392
|
-
def is_root? node
|
393
|
-
node && @root && node.object_id == @root.object_id
|
394
|
-
end
|
395
|
-
|
396
|
-
def increment_size!
|
397
|
-
@size += 1
|
398
|
-
end
|
399
|
-
|
400
|
-
def decrement_size!
|
401
|
-
@size -= 1
|
402
|
-
end
|
403
|
-
|
404
|
-
def update_left_most_node!
|
405
|
-
unless @root
|
406
|
-
@left_most_node = nil
|
407
|
-
return
|
408
|
-
end
|
409
|
-
|
410
|
-
current = @root
|
411
|
-
current = current.left until current.left.leaf?
|
412
|
-
@left_most_node = current
|
413
|
-
end
|
414
433
|
end
|
@@ -4,20 +4,27 @@ class RedBlackTree
|
|
4
4
|
class Node
|
5
5
|
module LeftRightElementReferencers # @private
|
6
6
|
def [] direction
|
7
|
+
validate_direction! direction
|
7
8
|
case direction
|
8
9
|
when Node::LEFT then @left
|
9
10
|
when Node::RIGHT then @right
|
10
|
-
else raise ArgumentError, "Direction must be one of #{Implementation::DIRECTIONS}, got #{direction}"
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
14
|
def []= direction, node
|
15
|
+
validate_direction! direction
|
15
16
|
case direction
|
16
17
|
when Node::LEFT then @left = node
|
17
18
|
when Node::RIGHT then @right = node
|
18
|
-
else raise ArgumentError, "Direction must be one of #{Implementation::DIRECTIONS}, got #{direction}"
|
19
19
|
end
|
20
20
|
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def validate_direction! direction
|
25
|
+
return if [Node::LEFT, Node::RIGHT].include?(direction)
|
26
|
+
raise ArgumentError, "Direction must be one of #{Implementation::DIRECTIONS}, got #{direction}"
|
27
|
+
end
|
21
28
|
end
|
22
29
|
end
|
23
30
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
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.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joshua Young
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date:
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
11
11
|
dependencies: []
|
12
12
|
email:
|
13
13
|
- djry1999@gmail.com
|
@@ -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: 3.6.
|
52
|
+
rubygems_version: 3.6.9
|
53
53
|
specification_version: 4
|
54
54
|
summary: Red-Black Tree Data Structure for Ruby
|
55
55
|
test_files: []
|