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.
@@ -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