rbtree-pure 0.1.0
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.
- data/.document +5 -0
- data/.project +17 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +20 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +17 -0
- data/Rakefile +57 -0
- data/VERSION +1 -0
- data/lib/rbtree.rb +10 -0
- data/lib/rbtree/guard_node.rb +28 -0
- data/lib/rbtree/multi_rb_tree.rb +317 -0
- data/lib/rbtree/node.rb +59 -0
- data/lib/rbtree/rb_tree.rb +485 -0
- data/lib/rbtree/tree.rb +382 -0
- data/lib/rbtree/tree_cmp.rb +92 -0
- data/old_ext/dict.c +1216 -0
- data/old_ext/dict.h +123 -0
- data/old_ext/rbtree.c +1706 -0
- data/test/helper.rb +17 -0
- data/test/multi_rbtree_test.rb +226 -0
- data/test/rbtree_test.rb +791 -0
- metadata +145 -0
data/lib/rbtree/tree.rb
ADDED
@@ -0,0 +1,382 @@
|
|
1
|
+
# :nodoc: namespace
|
2
|
+
class RBTree
|
3
|
+
|
4
|
+
# Red-black tree implementation based on "Introduction to Algorithms" by CLRS.
|
5
|
+
#
|
6
|
+
# Instances of this class are not thread-safe. However, using different
|
7
|
+
# instances in different threads is OK, unlike the original RedBlackTree class.
|
8
|
+
class Tree
|
9
|
+
# The tree's root node.
|
10
|
+
attr_reader :root
|
11
|
+
|
12
|
+
# The number of nodes in the tree.
|
13
|
+
attr_reader :size
|
14
|
+
|
15
|
+
# The tree's guard node.
|
16
|
+
attr_reader :guard
|
17
|
+
protected :guard
|
18
|
+
|
19
|
+
# Creates a new tree.
|
20
|
+
def initialize
|
21
|
+
@guard = GuardNode.new
|
22
|
+
@size = 0
|
23
|
+
@root = @guard
|
24
|
+
end
|
25
|
+
|
26
|
+
# Makes a deep copy of the source's tree, but uses the original keys & values.
|
27
|
+
def initialize_copy(source)
|
28
|
+
super
|
29
|
+
@guard = GuardNode.new
|
30
|
+
@root = clone_tree source.root, source.guard
|
31
|
+
end
|
32
|
+
|
33
|
+
# Produces a copy of a subtree.
|
34
|
+
#
|
35
|
+
# Arg:
|
36
|
+
# root:: the root node of the subtree to be copied
|
37
|
+
# source_guard:: the guard node of the RBTree containing root
|
38
|
+
#
|
39
|
+
# Returns the root of the new subtree.
|
40
|
+
def clone_tree(root, source_guard)
|
41
|
+
return @guard if root == source_guard
|
42
|
+
new_root = RBTree::Node.new root.key, root.value, @guard
|
43
|
+
new_root.color = root.color
|
44
|
+
new_root.left = clone_tree root.left, source_guard
|
45
|
+
new_root.left.parent = new_root unless new_root.left == @guard
|
46
|
+
new_root.right = clone_tree root.right, source_guard
|
47
|
+
new_root.right.parent = new_root unless new_root.right == @guard
|
48
|
+
new_root
|
49
|
+
end
|
50
|
+
private :clone_tree
|
51
|
+
|
52
|
+
# Creates a new node holding a given key and value.
|
53
|
+
def node(key, value)
|
54
|
+
RBTree::Node.new key, value, @guard
|
55
|
+
end
|
56
|
+
|
57
|
+
# Adds a new Node to the tree.
|
58
|
+
#
|
59
|
+
# Returns the given node, if it was inserted into the tree. If a node with
|
60
|
+
# same key already existed, that node is returned instead, and the given node
|
61
|
+
# is not inserted into the tree.
|
62
|
+
def insert(node)
|
63
|
+
x = insert_helper node
|
64
|
+
return x unless x == node
|
65
|
+
|
66
|
+
x.color = :red
|
67
|
+
while x != @root && x.parent.color == :red
|
68
|
+
if x.parent == x.parent.parent.left
|
69
|
+
y = x.parent.parent.right
|
70
|
+
if !y.nil? && y.color == :red
|
71
|
+
x.parent.color = :black
|
72
|
+
y.color = :black
|
73
|
+
x.parent.parent.color = :red
|
74
|
+
x = x.parent.parent
|
75
|
+
else
|
76
|
+
if x == x.parent.right
|
77
|
+
x = x.parent
|
78
|
+
left_rotate x
|
79
|
+
end
|
80
|
+
x.parent.color = :black
|
81
|
+
x.parent.parent.color = :red
|
82
|
+
right_rotate x.parent.parent
|
83
|
+
end
|
84
|
+
else
|
85
|
+
y = x.parent.parent.left
|
86
|
+
if !y.nil? && y.color == :red
|
87
|
+
x.parent.color = :black
|
88
|
+
y.color = :black
|
89
|
+
x.parent.parent.color = :red
|
90
|
+
x = x.parent.parent
|
91
|
+
else
|
92
|
+
if x == x.parent.left
|
93
|
+
x = x.parent
|
94
|
+
right_rotate x
|
95
|
+
end
|
96
|
+
x.parent.color = :black
|
97
|
+
x.parent.parent.color = :red
|
98
|
+
left_rotate x.parent.parent
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
@root.color = :black
|
103
|
+
node
|
104
|
+
end
|
105
|
+
|
106
|
+
# Removes a node from the tree.
|
107
|
+
def delete(z)
|
108
|
+
y = (z.left.nil? || z.right.nil?) ? z : successor(z)
|
109
|
+
x = y.left.nil? ? y.right : y.left
|
110
|
+
x.parent = y.parent
|
111
|
+
|
112
|
+
if y.parent.nil?
|
113
|
+
@root = x
|
114
|
+
else
|
115
|
+
if y == y.parent.left
|
116
|
+
y.parent.left = x
|
117
|
+
else
|
118
|
+
y.parent.right = x
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
if y != z
|
123
|
+
z.key = y.key
|
124
|
+
z.value = y.value
|
125
|
+
end
|
126
|
+
|
127
|
+
if y.color == :black
|
128
|
+
delete_fixup(x)
|
129
|
+
end
|
130
|
+
|
131
|
+
@size -= 1
|
132
|
+
y
|
133
|
+
end
|
134
|
+
|
135
|
+
# The node with lowest key in the subtree rooted at the given node.
|
136
|
+
def minimum(node = root)
|
137
|
+
while !node.left.nil?
|
138
|
+
node = node.left
|
139
|
+
end
|
140
|
+
node
|
141
|
+
end
|
142
|
+
|
143
|
+
# The node with the highest key in the subtree rooted at the given node.
|
144
|
+
def maximum(node = root)
|
145
|
+
while !node.right.nil?
|
146
|
+
node = node.right
|
147
|
+
end
|
148
|
+
node
|
149
|
+
end
|
150
|
+
|
151
|
+
# The node with the lowest key that is higher than the given node's key.
|
152
|
+
def successor(x)
|
153
|
+
return minimum(x.right) unless x.right.nil?
|
154
|
+
|
155
|
+
y = x.parent
|
156
|
+
while !y.nil? && x == y.right
|
157
|
+
x = y
|
158
|
+
y = y.parent
|
159
|
+
end
|
160
|
+
y
|
161
|
+
end
|
162
|
+
|
163
|
+
# The node with the highest key that is lower than the given node's key.
|
164
|
+
def predecessor(x)
|
165
|
+
return maximum(x.left) unless x.left.nil?
|
166
|
+
|
167
|
+
y = x.parent
|
168
|
+
while !y.nil? && x == y.left
|
169
|
+
x = y
|
170
|
+
y = y.parent
|
171
|
+
end
|
172
|
+
y
|
173
|
+
end
|
174
|
+
|
175
|
+
# Yields all nodes in the given node's subtree, in ascending key order.
|
176
|
+
def inorder(node = root)
|
177
|
+
node = self.minimum
|
178
|
+
until node.nil?
|
179
|
+
yield node
|
180
|
+
node = successor node
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
# Yields all nodes in the given node's subtree, in descending key order.
|
185
|
+
def reverse_inorder(node = root)
|
186
|
+
node = self.maximum
|
187
|
+
until node.nil?
|
188
|
+
yield node
|
189
|
+
node = predecessor node
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
# Returns a node containing the given key or nil if no node contains the key.
|
194
|
+
def search(key, node = root)
|
195
|
+
until node.nil?
|
196
|
+
return node if node.key == key
|
197
|
+
node = ((key <=> node.key) < 0) ? node.left : node.right
|
198
|
+
end
|
199
|
+
nil
|
200
|
+
end
|
201
|
+
|
202
|
+
# Returns the node with the smallest key that is >= the given key.
|
203
|
+
#
|
204
|
+
# Returns nil if called on an empty tree or the guard node.
|
205
|
+
def lower_bound(key, node = root)
|
206
|
+
return nil if node.nil?
|
207
|
+
loop do
|
208
|
+
cmp = key <=> node.key
|
209
|
+
return node if cmp == 0
|
210
|
+
if cmp < 0
|
211
|
+
next_node = node.left
|
212
|
+
return node if next_node.nil?
|
213
|
+
else
|
214
|
+
next_node = node.right
|
215
|
+
return successor(node) if next_node.nil?
|
216
|
+
end
|
217
|
+
node = next_node
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
# Returns a node with the largest key that is <= then given key.
|
222
|
+
#
|
223
|
+
# Returns nil if called on an empty tree or the guard node.
|
224
|
+
def upper_bound(key, node = root)
|
225
|
+
return nil if node.nil?
|
226
|
+
loop do
|
227
|
+
cmp = key <=> node.key
|
228
|
+
return node if cmp == 0
|
229
|
+
if cmp < 0
|
230
|
+
next_node = node.left
|
231
|
+
return predecessor(node) if next_node.nil?
|
232
|
+
else
|
233
|
+
next_node = node.right
|
234
|
+
return node if next_node.nil?
|
235
|
+
end
|
236
|
+
node = next_node
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
# True if the tree has no nodes in it.
|
241
|
+
def empty?
|
242
|
+
@root.nil?
|
243
|
+
end
|
244
|
+
|
245
|
+
# Number of black nodes on each path from the given node to a leaf.
|
246
|
+
#
|
247
|
+
# Red-black trees have the same number of black nodes on all paths from the
|
248
|
+
# root to leaves, so this function is well defined.
|
249
|
+
def black_height(node = root)
|
250
|
+
height = 0
|
251
|
+
while !node.nil?
|
252
|
+
node = node.left
|
253
|
+
height += 1 if node.nil? || node.black?
|
254
|
+
end
|
255
|
+
height
|
256
|
+
end
|
257
|
+
|
258
|
+
private
|
259
|
+
|
260
|
+
def left_rotate(x)
|
261
|
+
raise "x.right is nil!" if x.right.nil?
|
262
|
+
y = x.right
|
263
|
+
x.right = y.left
|
264
|
+
y.left.parent = x if !y.left.nil?
|
265
|
+
y.parent = x.parent
|
266
|
+
if x.parent.nil?
|
267
|
+
@root = y
|
268
|
+
else
|
269
|
+
if x == x.parent.left
|
270
|
+
x.parent.left = y
|
271
|
+
else
|
272
|
+
x.parent.right = y
|
273
|
+
end
|
274
|
+
end
|
275
|
+
y.left = x
|
276
|
+
x.parent = y
|
277
|
+
end
|
278
|
+
|
279
|
+
def right_rotate(x)
|
280
|
+
raise "x.left is nil!" if x.left.nil?
|
281
|
+
y = x.left
|
282
|
+
x.left = y.right
|
283
|
+
y.right.parent = x if !y.right.nil?
|
284
|
+
y.parent = x.parent
|
285
|
+
if x.parent.nil?
|
286
|
+
@root = y
|
287
|
+
else
|
288
|
+
if x == x.parent.left
|
289
|
+
x.parent.left = y
|
290
|
+
else
|
291
|
+
x.parent.right = y
|
292
|
+
end
|
293
|
+
end
|
294
|
+
y.right = x
|
295
|
+
x.parent = y
|
296
|
+
end
|
297
|
+
|
298
|
+
def insert_helper(z)
|
299
|
+
y = @guard
|
300
|
+
x = @root
|
301
|
+
key = z.key
|
302
|
+
until x.nil?
|
303
|
+
y = x
|
304
|
+
unless cmp = x.key <=> key
|
305
|
+
raise ArgumentError,
|
306
|
+
"comparison of #{x.key.class} with #{key.inspect} failed"
|
307
|
+
end
|
308
|
+
if cmp > 0
|
309
|
+
x = x.left
|
310
|
+
elsif cmp < 0
|
311
|
+
x = x.right
|
312
|
+
else
|
313
|
+
return x
|
314
|
+
end
|
315
|
+
end
|
316
|
+
z.parent = y
|
317
|
+
if y.nil?
|
318
|
+
@root = z
|
319
|
+
else
|
320
|
+
((key <=> y.key) < 0) ? y.left = z : y.right = z
|
321
|
+
end
|
322
|
+
@size += 1
|
323
|
+
z
|
324
|
+
end
|
325
|
+
|
326
|
+
def delete_fixup(x)
|
327
|
+
while x != root && x.color == :black
|
328
|
+
if x == x.parent.left
|
329
|
+
w = x.parent.right
|
330
|
+
if w.color == :red
|
331
|
+
w.color = :black
|
332
|
+
x.parent.color = :red
|
333
|
+
left_rotate x.parent
|
334
|
+
w = x.parent.right
|
335
|
+
end
|
336
|
+
if w.left.color == :black && w.right.color == :black
|
337
|
+
w.color = :red
|
338
|
+
x = x.parent
|
339
|
+
else
|
340
|
+
if w.right.color == :black
|
341
|
+
w.left.color = :black
|
342
|
+
w.color = :red
|
343
|
+
right_rotate w
|
344
|
+
w = x.parent.right
|
345
|
+
end
|
346
|
+
w.color = x.parent.color
|
347
|
+
x.parent.color = :black
|
348
|
+
w.right.color = :black
|
349
|
+
left_rotate x.parent
|
350
|
+
x = root
|
351
|
+
end
|
352
|
+
else
|
353
|
+
w = x.parent.left
|
354
|
+
if w.color == :red
|
355
|
+
w.color = :black
|
356
|
+
x.parent.color = :red
|
357
|
+
right_rotate x.parent
|
358
|
+
w = x.parent.left
|
359
|
+
end
|
360
|
+
if w.right.color == :black && w.left.color == :black
|
361
|
+
w.color = :red
|
362
|
+
x = x.parent
|
363
|
+
else
|
364
|
+
if w.left.color == :black
|
365
|
+
w.right.color = :black
|
366
|
+
w.color = :red
|
367
|
+
left_rotate w
|
368
|
+
w = x.parent.left
|
369
|
+
end
|
370
|
+
w.color = x.parent.color
|
371
|
+
x.parent.color = :black
|
372
|
+
w.left.color = :black
|
373
|
+
right_rotate x.parent
|
374
|
+
x = root
|
375
|
+
end
|
376
|
+
end
|
377
|
+
end
|
378
|
+
x.color = :black
|
379
|
+
end
|
380
|
+
end # class RBTree::Tree
|
381
|
+
|
382
|
+
end # class RBTree
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# :nodoc: namespace
|
2
|
+
class RBTree
|
3
|
+
|
4
|
+
# Variant of Tree that uses a custom comparator.
|
5
|
+
#
|
6
|
+
# This is the "slow path", whereas Tree uses "fast path" <, > etc.
|
7
|
+
class TreeCmp < Tree
|
8
|
+
# Creates a new tree.
|
9
|
+
def initialize(&cmp_proc)
|
10
|
+
@cmp_proc = cmp_proc
|
11
|
+
@guard = GuardNode.new
|
12
|
+
@size = 0
|
13
|
+
@root = @guard
|
14
|
+
end
|
15
|
+
|
16
|
+
# Returns a node containing the given key or nil if no node contains the key.
|
17
|
+
def search(key, node = root)
|
18
|
+
until node.nil?
|
19
|
+
return node if node.key == key
|
20
|
+
node = @cmp_proc.call(key, node.key) < 0 ? node.left : node.right
|
21
|
+
end
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
|
25
|
+
# Returns the node with the smallest key that is >= the given key.
|
26
|
+
#
|
27
|
+
# Returns nil if called on an empty tree or the guard node.
|
28
|
+
def lower_bound(key, node = root)
|
29
|
+
return nil if node.nil?
|
30
|
+
loop do
|
31
|
+
cmp = @cmp_proc.call(key, node.key)
|
32
|
+
return node if cmp == 0
|
33
|
+
if cmp < 0
|
34
|
+
next_node = node.left
|
35
|
+
return node if next_node.nil?
|
36
|
+
else
|
37
|
+
next_node = node.right
|
38
|
+
return successor(node) if next_node.nil?
|
39
|
+
end
|
40
|
+
node = next_node
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Returns a node with the largest key that is <= then given key.
|
45
|
+
#
|
46
|
+
# Returns nil if called on an empty tree or the guard node.
|
47
|
+
def upper_bound(key, node = root)
|
48
|
+
return nil if node.nil?
|
49
|
+
loop do
|
50
|
+
cmp = @cmp_proc.call(key, node.key)
|
51
|
+
return node if cmp == 0
|
52
|
+
if cmp < 0
|
53
|
+
next_node = node.left
|
54
|
+
return predecessor(node) if next_node.nil?
|
55
|
+
else
|
56
|
+
next_node = node.right
|
57
|
+
return node if next_node.nil?
|
58
|
+
end
|
59
|
+
node = next_node
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def insert_helper(z)
|
64
|
+
y = @guard
|
65
|
+
x = @root
|
66
|
+
key = z.key
|
67
|
+
until x.nil?
|
68
|
+
y = x
|
69
|
+
unless cmp = @cmp_proc.call(x.key, key)
|
70
|
+
raise ArgumentError,
|
71
|
+
"comparison of #{x.key.class} with #{key.inspect} failed"
|
72
|
+
end
|
73
|
+
if cmp > 0
|
74
|
+
x = x.left
|
75
|
+
elsif cmp < 0
|
76
|
+
x = x.right
|
77
|
+
else
|
78
|
+
return x
|
79
|
+
end
|
80
|
+
end
|
81
|
+
z.parent = y
|
82
|
+
if y.nil?
|
83
|
+
@root = z
|
84
|
+
else
|
85
|
+
@cmp_proc.call(key, y.key) < 0 ? y.left = z : y.right = z
|
86
|
+
end
|
87
|
+
@size += 1
|
88
|
+
z
|
89
|
+
end
|
90
|
+
end # class RBTree::TreeCmp
|
91
|
+
|
92
|
+
end # class RBTree
|