rbtree-pure 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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