tree-red_black 0.4.2
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 +7 -0
- data/.gitignore +12 -0
- data/.travis.yml +10 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +36 -0
- data/LICENSE.txt +21 -0
- data/README.md +572 -0
- data/Rakefile +12 -0
- data/contrib/iterate_dot_graphs.rb +208 -0
- data/lib/tree-red_black.rb +1 -0
- data/lib/tree/red_black.rb +243 -0
- data/lib/tree/red_black/red_black_node.rb +645 -0
- data/lib/tree/red_black/version.rb +6 -0
- data/tree-red_black.gemspec +31 -0
- metadata +122 -0
@@ -0,0 +1,645 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
module Tree
|
3
|
+
##
|
4
|
+
# Tree::RedBlackNode is a pure-Ruby implementation of a
|
5
|
+
# {Red-Black tree}[https://en.wikipedia.org/wiki/Red–black_tree] --
|
6
|
+
# i.e., a self-balancing binary search tree with
|
7
|
+
# {O(log n)}[https://en.wikipedia.org/wiki/Big-O_notation]
|
8
|
+
# search, insert and delete operations. It is appropriate for
|
9
|
+
# maintaining an ordered collection where insertion and deletion
|
10
|
+
# are desired at arbitrary positions.
|
11
|
+
#
|
12
|
+
# The implementation differs slightly from the Wikipedia description
|
13
|
+
# referenced above. In particular, leaf nodes are +nil+, which
|
14
|
+
# affects the details of node deletion.
|
15
|
+
#
|
16
|
+
# While a Red-Black tree can be constructed from nodes alone, the
|
17
|
+
# Tree::RedBlack API provides a cleaner way of working with
|
18
|
+
# Red-Black trees. Start there if only using the Red-Black tree as a
|
19
|
+
# container.
|
20
|
+
|
21
|
+
class RedBlackNode
|
22
|
+
include Enumerable
|
23
|
+
|
24
|
+
attr_accessor :left, :right, :key, :parent, :color
|
25
|
+
|
26
|
+
##
|
27
|
+
# Returns a new node with +key+ parameter set to option +value+.
|
28
|
+
# The +color+ option, if given, must be be either <tt>:RED</tt> or
|
29
|
+
# <tt>:BLACK</tt>.
|
30
|
+
#
|
31
|
+
# A Red-Black tree is a collection of nodes arranged as a binary tree.
|
32
|
+
# In addition to the binary node attributes `left` and `right`, which
|
33
|
+
# reference the left and right sub-trees of a given node, and the
|
34
|
+
# attribute `key` which stores a node's data, a Red-Black tree node
|
35
|
+
# also has attributes `color` and `parent`.
|
36
|
+
#
|
37
|
+
# The `color` attribute is used internally to balance the tree after a
|
38
|
+
# node is inserted or deleted. The `parent` attribute references a
|
39
|
+
# node's parent, or `nil` in the case of the root node of a tree.
|
40
|
+
|
41
|
+
#
|
42
|
+
# === Example
|
43
|
+
#
|
44
|
+
# require 'tree/red_black'
|
45
|
+
#
|
46
|
+
# root = Tree::RedBlackNode.new(10)
|
47
|
+
# p root.key #=> 10
|
48
|
+
# p root.color #=> :RED
|
49
|
+
# p root.parent #=> nil
|
50
|
+
# p root.left #=> nil
|
51
|
+
# p root.right #=> nil
|
52
|
+
|
53
|
+
def initialize(value = nil, color = :RED)
|
54
|
+
raise "color must be :RED or :BLACK" unless [:RED, :BLACK].include?(color)
|
55
|
+
|
56
|
+
@left = @right = @parent = nil
|
57
|
+
@key = value
|
58
|
+
@color = color
|
59
|
+
end
|
60
|
+
|
61
|
+
def <=>(other) # :nodoc:
|
62
|
+
key <=> other.key
|
63
|
+
end
|
64
|
+
|
65
|
+
def sibling # :nodoc:
|
66
|
+
self == parent&.left ? parent&.right : parent&.left
|
67
|
+
end
|
68
|
+
|
69
|
+
def grandparent # :nodoc:
|
70
|
+
parent&.parent
|
71
|
+
end
|
72
|
+
|
73
|
+
def parent_sibling # :nodoc:
|
74
|
+
parent&.sibling
|
75
|
+
end
|
76
|
+
|
77
|
+
##
|
78
|
+
# Inserts the given +value+ in a tree whose root node is +self+.
|
79
|
+
# If the +key+ attribute of the root node is +nil+, then +value+
|
80
|
+
# is assigned to +key+. Otherwise, +value+ is used to instantiate
|
81
|
+
# a Tree::RedBlackNode, and the node is inserted in the tree; the
|
82
|
+
# tree is then re-balanced as needed, and the root of the balanced
|
83
|
+
# tree returned.
|
84
|
+
|
85
|
+
# Since a Red-Black tree maintains an ordered, Enumerable
|
86
|
+
# collection, every value inserted must be Comparable with every
|
87
|
+
# other value. Methods +each+, +map+, +select+, +find+, +sort+,
|
88
|
+
# etc., can be applied to a Red-Black tree's root node to iterate
|
89
|
+
# over all nodes in the tree.
|
90
|
+
#
|
91
|
+
# Each node yielded by enumeration has a +key+ attribute to
|
92
|
+
# retrieve the value stored in that node. Method +each+, in
|
93
|
+
# particular, is aliased to +in_order+, so that nodes are sorted
|
94
|
+
# in ascending order by +key+ value. Nodes can also be traversed
|
95
|
+
# by method +pre_order+, e.g., to generate paths in the tree.
|
96
|
+
#
|
97
|
+
# === Example
|
98
|
+
#
|
99
|
+
# require 'tree/red_black'
|
100
|
+
#
|
101
|
+
# root = Tree::RedBlackNode.new
|
102
|
+
# p root.key #=> nil
|
103
|
+
# root = root.insert_red_black(0)
|
104
|
+
# p root.key #=> 0
|
105
|
+
# root = root.insert_red_black(1)
|
106
|
+
# p root.key #=> 0
|
107
|
+
# p root.left #=> nil
|
108
|
+
# p root.right.key #=> 1
|
109
|
+
# root = root.insert_red_black(2)
|
110
|
+
# p root.key #=> 1
|
111
|
+
# p root.left.key #=> 0
|
112
|
+
# p root.right.key #=> 2
|
113
|
+
|
114
|
+
def insert_red_black(value, allow_duplicates = true)
|
115
|
+
node = allow_duplicates ? insert_key(value) : insert_unique_key(value)
|
116
|
+
|
117
|
+
return nil if node.nil?
|
118
|
+
|
119
|
+
node.color_insert
|
120
|
+
|
121
|
+
while node.parent
|
122
|
+
node = node.parent
|
123
|
+
end
|
124
|
+
node
|
125
|
+
end
|
126
|
+
|
127
|
+
##
|
128
|
+
# Deletes the given +value+ from a tree whose root node is +self+.
|
129
|
+
# If the tree has only one remaining node and its +key+ attribute
|
130
|
+
# matches +value+, then the remaining node's +key+ attribute is
|
131
|
+
# set to +nil+ but the node itself is not removed. Otherwise, the
|
132
|
+
# first node found whose +key+ matches +value+ is removed from the
|
133
|
+
# tree, and the tree is re-balanced. The root of the balanced tree
|
134
|
+
# is returned.
|
135
|
+
#
|
136
|
+
# === Example
|
137
|
+
#
|
138
|
+
# require 'tree/red_black'
|
139
|
+
#
|
140
|
+
# root = [*1..10].reduce(Tree::RedBlackNode.new) do |acc, v|
|
141
|
+
# acc.insert_red_black(v)
|
142
|
+
# end
|
143
|
+
# root = [*4..8].reduce(root) do |acc, v|
|
144
|
+
# acc.delete_red_black(v)
|
145
|
+
# end
|
146
|
+
# root.map(&:key) #=> [1, 2, 3, 9, 10]
|
147
|
+
|
148
|
+
def delete_red_black(value)
|
149
|
+
if key.nil?
|
150
|
+
nil
|
151
|
+
elsif value > key
|
152
|
+
right ? right.delete_red_black(value) : nil
|
153
|
+
elsif value < key
|
154
|
+
left ? left.delete_red_black(value) : nil
|
155
|
+
else
|
156
|
+
if left && right
|
157
|
+
node = right.min
|
158
|
+
@key = node.key
|
159
|
+
node.substitute_with_child
|
160
|
+
else
|
161
|
+
substitute_with_child
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
##
|
167
|
+
# Returns a node whose +key+ matches +value+ by binary search. If no
|
168
|
+
# match is found, calls non-nil +ifnone+, otherwise returns +nil+.
|
169
|
+
#
|
170
|
+
# === Example
|
171
|
+
# require 'tree/red_black'
|
172
|
+
#
|
173
|
+
# shuffled_values = [*1..10].shuffle
|
174
|
+
# root = shuffled_values.reduce(Tree::RedBlackNode.new) do |acc, v|
|
175
|
+
# acc.insert_red_black(v)
|
176
|
+
# end
|
177
|
+
# root.search(7) #=> <Tree::RedBlackNode:0x00..., @key=7, ...>
|
178
|
+
|
179
|
+
def search(value, ifnone = nil)
|
180
|
+
if key.nil?
|
181
|
+
ifnone && ifnone.call
|
182
|
+
elsif value > key
|
183
|
+
right ? right.search(value, ifnone) : ifnone && ifnone.call
|
184
|
+
elsif value < key
|
185
|
+
left ? left.search(value, ifnone) : ifnone && ifnone.call
|
186
|
+
else
|
187
|
+
self
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
##
|
192
|
+
# Returns a node satisfying a criterion defined in +block+ by
|
193
|
+
# binary search.
|
194
|
+
#
|
195
|
+
# If +block+ evaluates to +true+ or +false+, returns the first node
|
196
|
+
# for which the +block+ evaluates to +true+. In this case, the
|
197
|
+
# criterion is expected to return +false+ for nodes preceding
|
198
|
+
# the matching node and +true+ for subsequent nodes.
|
199
|
+
#
|
200
|
+
# === Example
|
201
|
+
# require 'tree/red_black'
|
202
|
+
#
|
203
|
+
# shuffled_values = [*1..10].shuffle
|
204
|
+
# root = shuffled_values.reduce(Tree::RedBlackNode.new) do |acc, v|
|
205
|
+
# acc.insert_red_black(v)
|
206
|
+
# end
|
207
|
+
# root.bsearch { |node| node.key >= 7 }
|
208
|
+
# #=> <Tree::RedBlackNode:0x00... @key=7 ...>
|
209
|
+
#
|
210
|
+
# If +block+ evaluates to <tt><0</tt>, +0+ or <tt>>0</tt>, returns
|
211
|
+
# first node for which +block+ evaluates to +0+. Otherwise returns
|
212
|
+
# +nil+. In this case, the criterion is expected to return
|
213
|
+
# <tt><0</tt> for nodes preceding the matching node, +0+ for some
|
214
|
+
# subsequent nodes and <tt>>0</tt> for nodes beyond that.
|
215
|
+
#
|
216
|
+
# === Example
|
217
|
+
# require 'tree/red_black'
|
218
|
+
#
|
219
|
+
# shuffled_values = [*1..10].shuffle
|
220
|
+
# root = shuffled_values.reduce(Tree::RedBlackNode.new) do |acc, v|
|
221
|
+
# acc.insert_red_black(v)
|
222
|
+
# end
|
223
|
+
# root.bsearch { |node| 7 <=> node.key }
|
224
|
+
# #=> <Tree::RedBlackNode:0x00... @key=7 ...>
|
225
|
+
#
|
226
|
+
# If +block++ is not given, returns an enumerator.
|
227
|
+
|
228
|
+
def bsearch(&block)
|
229
|
+
return enum_for(:bsearch) unless block_given?
|
230
|
+
|
231
|
+
return nil if key.nil?
|
232
|
+
|
233
|
+
result = block.call(self)
|
234
|
+
case result
|
235
|
+
when Integer
|
236
|
+
if result > 0
|
237
|
+
right ? right.bsearch(&block) : nil
|
238
|
+
elsif result < 0
|
239
|
+
left ? left.bsearch(&block) : nil
|
240
|
+
else
|
241
|
+
self
|
242
|
+
end
|
243
|
+
when TrueClass, FalseClass
|
244
|
+
if result
|
245
|
+
left ? (node = left.bsearch(&block); node ? node : self) : self
|
246
|
+
else
|
247
|
+
right ? right.bsearch(&block) : nil
|
248
|
+
end
|
249
|
+
else
|
250
|
+
nil
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
##
|
255
|
+
# Returns the node whose +key+ is a minimum in the sub-tree with
|
256
|
+
# root +self+.
|
257
|
+
#
|
258
|
+
# === Example
|
259
|
+
# require 'tree/red_black'
|
260
|
+
#
|
261
|
+
# root = [*0..10].reduce(Tree::RedBlackNode.new) do |acc, v|
|
262
|
+
# acc.insert_red_black(v)
|
263
|
+
# end
|
264
|
+
# root #=> <Tree::RedBlackNode:0x00..., @key=4, ...>
|
265
|
+
# root.min #=> <Tree::RedBlackNode:0x00..., @key=0, ...>
|
266
|
+
# root.right #=> <Tree::RedBlackNode:0x00..., @key=6, ...>
|
267
|
+
# root.right.min #=> <Tree::RedBlackNode:0x00..., @key=5, ...>
|
268
|
+
|
269
|
+
def min
|
270
|
+
node = self
|
271
|
+
while node.left
|
272
|
+
node = node.left
|
273
|
+
end
|
274
|
+
node
|
275
|
+
end
|
276
|
+
|
277
|
+
##
|
278
|
+
# Returns the node whose +key+ is a maximum in the sub-tree with
|
279
|
+
# root +self+.
|
280
|
+
#
|
281
|
+
# === Example
|
282
|
+
# require 'tree/red_black'
|
283
|
+
#
|
284
|
+
# root = [*0..10].reduce(Tree::RedBlackNode.new) do |acc, v|
|
285
|
+
# acc.insert_red_black(v)
|
286
|
+
# end
|
287
|
+
# root #=> <Tree::RedBlackNode:0x00..., @key=4, ...>
|
288
|
+
# root.max #=> <Tree::RedBlackNode:0x00..., @key=10, ...>
|
289
|
+
# root.left #=> <Tree::RedBlackNode:0x00..., @key=2, ...>
|
290
|
+
# root.left.max #=> <Tree::RedBlackNode:0x00..., @key=3, ...>
|
291
|
+
|
292
|
+
def max
|
293
|
+
node = self
|
294
|
+
while node.right
|
295
|
+
node = node.right
|
296
|
+
end
|
297
|
+
node
|
298
|
+
end
|
299
|
+
|
300
|
+
##
|
301
|
+
# Returns the node preceding +self+, or +nil+ if no predecessor
|
302
|
+
# exists. If duplicate keys are allowed, it's possible that
|
303
|
+
# <tt>pred.key == key</tt>.
|
304
|
+
#
|
305
|
+
# === Example
|
306
|
+
# require 'tree/red_black'
|
307
|
+
#
|
308
|
+
# root = [*1..10].reduce(Tree::RedBlackNode.new) do |acc, v|
|
309
|
+
# acc.insert_red_black(v)
|
310
|
+
# end
|
311
|
+
# root.right.right.key #=> 8
|
312
|
+
# root.right.right.pred.key #=> 7
|
313
|
+
|
314
|
+
def pred
|
315
|
+
return left.max if left
|
316
|
+
|
317
|
+
node = parent
|
318
|
+
while node && node.key > key
|
319
|
+
node = node.parent
|
320
|
+
end
|
321
|
+
node
|
322
|
+
end
|
323
|
+
|
324
|
+
##
|
325
|
+
# Returns the node succeeding +self+, or +nil+ if no successor
|
326
|
+
# exists. If duplicate keys are allowed, it's possible that
|
327
|
+
# <tt>succ.key == key</tt>.
|
328
|
+
#
|
329
|
+
# === Example
|
330
|
+
# require 'tree/red_black'
|
331
|
+
#
|
332
|
+
# root = [*1..10].reduce(Tree::RedBlackNode.new) do |acc, v|
|
333
|
+
# acc.insert_red_black(v)
|
334
|
+
# end
|
335
|
+
# root.right.right.key #=> 8
|
336
|
+
# root.right.right.succ.key #=> 9
|
337
|
+
|
338
|
+
def succ
|
339
|
+
return right.min if right
|
340
|
+
|
341
|
+
node = parent
|
342
|
+
while node && node.key < key
|
343
|
+
node = node.parent
|
344
|
+
end
|
345
|
+
node
|
346
|
+
end
|
347
|
+
|
348
|
+
##
|
349
|
+
# Returns an enumerator for nodes in the tree with root +self+ by
|
350
|
+
# pre-order traversal.
|
351
|
+
#
|
352
|
+
# === Example
|
353
|
+
# require 'tree/red_black'
|
354
|
+
#
|
355
|
+
# root = [*1..10].reduce(Tree::RedBlackNode.new) do |acc, v|
|
356
|
+
# acc.insert_red_black(v)
|
357
|
+
# end
|
358
|
+
# root.pre_order.map(&:key) #=> [4, 2, 1, 3, 6, 5, 8, 7, 9, 10]
|
359
|
+
|
360
|
+
def pre_order(&block)
|
361
|
+
return enum_for(:pre_order) unless block_given?
|
362
|
+
|
363
|
+
yield self
|
364
|
+
left.pre_order(&block) if left
|
365
|
+
right.pre_order(&block) if right
|
366
|
+
end
|
367
|
+
|
368
|
+
##
|
369
|
+
# Returns an enumerator for nodes in the tree with root +self+ by
|
370
|
+
# in-order traversal.
|
371
|
+
#
|
372
|
+
# === Example
|
373
|
+
# require 'tree/red_black'
|
374
|
+
#
|
375
|
+
# shuffled_values = [*1..10].shuffle
|
376
|
+
# root = shuffled_values.reduce(Tree::RedBlackNode.new) do |acc, v|
|
377
|
+
# acc.insert_red_black(v)
|
378
|
+
# end
|
379
|
+
# root.in_order.map(&:key) #=> [1, 2, ..., 10]
|
380
|
+
|
381
|
+
def in_order(&block)
|
382
|
+
return enum_for(:in_order) unless block_given?
|
383
|
+
|
384
|
+
left.in_order(&block) if left
|
385
|
+
yield self
|
386
|
+
right.in_order(&block) if right
|
387
|
+
end
|
388
|
+
|
389
|
+
##
|
390
|
+
# Returns a deep copy of the tree with root +self+, provided that
|
391
|
+
# the +dup+ method for the +key+ attribute of a node is also a
|
392
|
+
# deep copy.
|
393
|
+
#
|
394
|
+
# === Example
|
395
|
+
#
|
396
|
+
# require 'tree/red_black'
|
397
|
+
#
|
398
|
+
# root = Tree::RedBlackNode.new({a: 1, b: 2})
|
399
|
+
# root_copy = root.dup
|
400
|
+
# p root.key #=> {:a=>1, :b=>2}
|
401
|
+
# p root.key.delete(:a) #=> 1
|
402
|
+
# p root.key #=> {:b=>2}
|
403
|
+
# p root_copy.key #=> {:a=>1, :b=>2}
|
404
|
+
|
405
|
+
def dup
|
406
|
+
copy = RedBlackNode.new(key.dup, color)
|
407
|
+
if left
|
408
|
+
copy.left = left.dup
|
409
|
+
copy.left.parent = copy
|
410
|
+
end
|
411
|
+
if right
|
412
|
+
copy.right = right.dup
|
413
|
+
copy.right.parent = copy
|
414
|
+
end
|
415
|
+
copy
|
416
|
+
end
|
417
|
+
|
418
|
+
def insert_key(value) # :nodoc:
|
419
|
+
if key.nil?
|
420
|
+
@key = value
|
421
|
+
self
|
422
|
+
elsif value >= key
|
423
|
+
if right
|
424
|
+
right.insert_key(value)
|
425
|
+
else
|
426
|
+
@right = RedBlackNode.new(value)
|
427
|
+
@right.parent = self
|
428
|
+
right
|
429
|
+
end
|
430
|
+
else
|
431
|
+
if left
|
432
|
+
left.insert_key(value)
|
433
|
+
else
|
434
|
+
@left = RedBlackNode.new(value)
|
435
|
+
@left.parent = self
|
436
|
+
left
|
437
|
+
end
|
438
|
+
end
|
439
|
+
end
|
440
|
+
|
441
|
+
def insert_unique_key(value) # :nodoc:
|
442
|
+
if key.nil?
|
443
|
+
@key = value
|
444
|
+
self
|
445
|
+
elsif value > key
|
446
|
+
if right
|
447
|
+
right.insert_unique_key(value)
|
448
|
+
else
|
449
|
+
@right = RedBlackNode.new(value)
|
450
|
+
@right.parent = self
|
451
|
+
right
|
452
|
+
end
|
453
|
+
elsif value < key
|
454
|
+
if left
|
455
|
+
left.insert_unique_key(value)
|
456
|
+
else
|
457
|
+
@left = RedBlackNode.new(value)
|
458
|
+
@left.parent = self
|
459
|
+
left
|
460
|
+
end
|
461
|
+
else
|
462
|
+
nil
|
463
|
+
end
|
464
|
+
end
|
465
|
+
|
466
|
+
def color_insert # :nodoc:
|
467
|
+
if parent.nil?
|
468
|
+
@color = :BLACK
|
469
|
+
elsif parent.color == :BLACK
|
470
|
+
return
|
471
|
+
elsif parent_sibling&.color == :RED
|
472
|
+
parent.color = parent_sibling.color = :BLACK
|
473
|
+
grandparent.color = :RED
|
474
|
+
grandparent.color_insert
|
475
|
+
else
|
476
|
+
node = if self == parent.right && parent == grandparent&.left
|
477
|
+
parent.rotate_left.left
|
478
|
+
elsif self == parent.left && parent == grandparent&.right
|
479
|
+
parent.rotate_right.right
|
480
|
+
else
|
481
|
+
self
|
482
|
+
end
|
483
|
+
node.parent.color = :BLACK
|
484
|
+
if node.grandparent
|
485
|
+
node.grandparent.color = :RED
|
486
|
+
if node == node.parent.left
|
487
|
+
node.grandparent.rotate_right
|
488
|
+
else
|
489
|
+
node.grandparent.rotate_left
|
490
|
+
end
|
491
|
+
end
|
492
|
+
end
|
493
|
+
end
|
494
|
+
|
495
|
+
def substitute_with_child # :nodoc:
|
496
|
+
if (child = right.nil? ? left : right)
|
497
|
+
child.parent = parent
|
498
|
+
child.color = :BLACK if color == :BLACK
|
499
|
+
end
|
500
|
+
|
501
|
+
if self == parent&.left
|
502
|
+
parent.left = child
|
503
|
+
parent.color_delete_left if (color == :BLACK && child.nil?)
|
504
|
+
elsif self == parent&.right
|
505
|
+
parent.right = child
|
506
|
+
parent.color_delete_right if (color == :BLACK && child.nil?)
|
507
|
+
end
|
508
|
+
|
509
|
+
node = parent ? parent : child
|
510
|
+
if node.nil?
|
511
|
+
@key = nil
|
512
|
+
self
|
513
|
+
else
|
514
|
+
while node.parent
|
515
|
+
node = node.parent
|
516
|
+
end
|
517
|
+
node
|
518
|
+
end
|
519
|
+
end
|
520
|
+
|
521
|
+
def color_delete_right # :nodoc:
|
522
|
+
child_sibling = left
|
523
|
+
|
524
|
+
if child_sibling.color == :RED
|
525
|
+
@color = :RED
|
526
|
+
child_sibling.color = :BLACK
|
527
|
+
rotate_right
|
528
|
+
child_sibling = left
|
529
|
+
end
|
530
|
+
|
531
|
+
if (color == :BLACK &&
|
532
|
+
child_sibling.color == :BLACK &&
|
533
|
+
(child_sibling.left.nil? || child_sibling.left.color == :BLACK) &&
|
534
|
+
(child_sibling.right.nil? || child_sibling.right.color == :BLACK))
|
535
|
+
child_sibling.color = :RED
|
536
|
+
if self == parent&.left
|
537
|
+
parent.color_delete_left
|
538
|
+
elsif self == parent&.right
|
539
|
+
parent.color_delete_right
|
540
|
+
end
|
541
|
+
elsif (color == :RED &&
|
542
|
+
child_sibling.color == :BLACK &&
|
543
|
+
(child_sibling.left.nil? || child_sibling.left.color == :BLACK) &&
|
544
|
+
(child_sibling.right.nil? || child_sibling.right.color == :BLACK))
|
545
|
+
child_sibling.color = :RED
|
546
|
+
@color = :BLACK
|
547
|
+
else
|
548
|
+
if child_sibling.color == :BLACK
|
549
|
+
if (child_sibling.right&.color == :RED &&
|
550
|
+
(child_sibling.left.nil? || child_sibling.left&.color == :BLACK))
|
551
|
+
child_sibling.color = :RED
|
552
|
+
child_sibling.right.color = :BLACK
|
553
|
+
child_sibling.rotate_left
|
554
|
+
child_sibling = left
|
555
|
+
end
|
556
|
+
end
|
557
|
+
|
558
|
+
child_sibling.color = color
|
559
|
+
@color = :BLACK
|
560
|
+
child_sibling.left.color = :BLACK # if child_sibling.left
|
561
|
+
rotate_right
|
562
|
+
end
|
563
|
+
end
|
564
|
+
|
565
|
+
def color_delete_left # :nodoc:
|
566
|
+
child_sibling = right
|
567
|
+
|
568
|
+
if child_sibling.color == :RED
|
569
|
+
@color = :RED
|
570
|
+
child_sibling.color = :BLACK
|
571
|
+
rotate_left
|
572
|
+
child_sibling = right
|
573
|
+
end
|
574
|
+
|
575
|
+
if (color == :BLACK &&
|
576
|
+
child_sibling.color == :BLACK &&
|
577
|
+
(child_sibling.left.nil? || child_sibling.left.color == :BLACK) &&
|
578
|
+
(child_sibling.right.nil? || child_sibling.right.color == :BLACK))
|
579
|
+
child_sibling.color = :RED
|
580
|
+
if self == parent&.left
|
581
|
+
parent.color_delete_left
|
582
|
+
elsif self == parent&.right
|
583
|
+
parent.color_delete_right
|
584
|
+
end
|
585
|
+
elsif (color == :RED &&
|
586
|
+
child_sibling.color == :BLACK &&
|
587
|
+
(child_sibling.left.nil? || child_sibling.left.color == :BLACK) &&
|
588
|
+
(child_sibling.right.nil? || child_sibling.right.color == :BLACK))
|
589
|
+
child_sibling.color = :RED
|
590
|
+
@color = :BLACK
|
591
|
+
else
|
592
|
+
if child_sibling.color == :BLACK
|
593
|
+
if ((child_sibling.right.nil? || child_sibling.right.color == :BLACK) &&
|
594
|
+
child_sibling.left&.color == :RED)
|
595
|
+
child_sibling.color = :RED
|
596
|
+
child_sibling.left.color = :BLACK
|
597
|
+
child_sibling.rotate_right
|
598
|
+
child_sibling = right
|
599
|
+
end
|
600
|
+
end
|
601
|
+
|
602
|
+
child_sibling.color = color
|
603
|
+
@color = :BLACK
|
604
|
+
child_sibling.right.color = :BLACK # if child_sibling.right
|
605
|
+
rotate_left
|
606
|
+
end
|
607
|
+
end
|
608
|
+
|
609
|
+
def rotate_right # :nodoc:
|
610
|
+
return self if left.nil?
|
611
|
+
|
612
|
+
root = left
|
613
|
+
root.right.parent = self unless (@left = root.right).nil?
|
614
|
+
if (root.parent = parent)
|
615
|
+
if self == parent.left
|
616
|
+
@parent.left = root
|
617
|
+
else
|
618
|
+
@parent.right = root
|
619
|
+
end
|
620
|
+
end
|
621
|
+
root.right = self
|
622
|
+
@parent = root
|
623
|
+
root
|
624
|
+
end
|
625
|
+
|
626
|
+
def rotate_left # :nodoc:
|
627
|
+
return self if right.nil?
|
628
|
+
|
629
|
+
root = right
|
630
|
+
root.left.parent = self unless (@right = root.left).nil?
|
631
|
+
if (root.parent = parent)
|
632
|
+
if self == parent.left
|
633
|
+
@parent.left = root
|
634
|
+
else
|
635
|
+
@parent.right = root
|
636
|
+
end
|
637
|
+
end
|
638
|
+
root.left = self
|
639
|
+
@parent = root
|
640
|
+
root
|
641
|
+
end
|
642
|
+
|
643
|
+
alias each in_order
|
644
|
+
end
|
645
|
+
end
|