stakach-algorithms 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,117 @@
1
+ require 'containers/heap'
2
+
3
+ =begin rdoc
4
+ A Priority Queue is a data structure that behaves like a queue except that elements have an
5
+ associated priority. The #next and #pop methods return the item with the next highest priority.
6
+
7
+ Priority Queues are often used in graph problems, such as Dijkstra's Algorithm for shortest
8
+ path, and the A* search algorithm for shortest path.
9
+
10
+ This container is implemented using the Fibonacci heap included in the Collections library.
11
+ =end
12
+ module Algorithms
13
+ module Containers
14
+ class PriorityQueue
15
+ include Enumerable
16
+
17
+ # Create a new, empty PriorityQueue
18
+ def initialize(&block)
19
+ # We default to a priority queue that returns the largest value
20
+ block ||= lambda { |x, y| (x <=> y) == 1 }
21
+ @heap = Heap.new(&block)
22
+ end
23
+
24
+ # Returns the number of elements in the queue.
25
+ #
26
+ # q = Algorithms::Containers::PriorityQueue.new
27
+ # q.size #=> 0
28
+ # q.push("Alaska", 1)
29
+ # q.size #=> 1
30
+ def size
31
+ @heap.size
32
+ end
33
+ alias_method :length, :size
34
+
35
+ # Add an object to the queue with associated priority.
36
+ #
37
+ # q = Algorithms::Containers::PriorityQueue.new
38
+ # q.push("Alaska", 1)
39
+ # q.pop #=> "Alaska"
40
+ def push(object, priority)
41
+ @heap.push(priority, object)
42
+ end
43
+
44
+ # Clears all the items in the queue.
45
+ def clear
46
+ @heap.clear
47
+ end
48
+
49
+ # Returns true if the queue is empty, false otherwise.
50
+ def empty?
51
+ @heap.empty?
52
+ end
53
+
54
+ # call-seq:
55
+ # has_priority? priority -> boolean
56
+ #
57
+ # Return true if the priority is in the queue, false otherwise.
58
+ #
59
+ # q = PriorityQueue.new
60
+ # q.push("Alaska", 1)
61
+ #
62
+ # q.has_priority?(1) #=> true
63
+ # q.has_priority?(2) #=> false
64
+ def has_priority?(priority)
65
+ @heap.has_key?(priority)
66
+ end
67
+
68
+ # call-seq:
69
+ # next -> object
70
+ #
71
+ # Return the object with the next highest priority, but does not remove it
72
+ #
73
+ # q = Algorithms::Containers::PriorityQueue.new
74
+ # q.push("Alaska", 50)
75
+ # q.push("Delaware", 30)
76
+ # q.push("Georgia", 35)
77
+ # q.next #=> "Alaska"
78
+ def next
79
+ @heap.next
80
+ end
81
+
82
+ # call-seq:
83
+ # pop -> object
84
+ #
85
+ # Return the object with the next highest priority and removes it from the queue
86
+ #
87
+ # q = Algorithms::Containers::PriorityQueue.new
88
+ # q.push("Alaska", 50)
89
+ # q.push("Delaware", 30)
90
+ # q.push("Georgia", 35)
91
+ # q.pop #=> "Alaska"
92
+ # q.size #=> 2
93
+ def pop
94
+ @heap.pop
95
+ end
96
+ alias_method :next!, :pop
97
+
98
+ # call-seq:
99
+ # delete(priority) -> object
100
+ # delete(priority) -> nil
101
+ #
102
+ # Delete an object with specified priority from the queue. If there are duplicates, an
103
+ # arbitrary object with that priority is deleted and returned. Returns nil if there are
104
+ # no objects with the priority.
105
+ #
106
+ # q = PriorityQueue.new
107
+ # q.push("Alaska", 50)
108
+ # q.push("Delaware", 30)
109
+ # q.delete(50) #=> "Alaska"
110
+ # q.delete(10) #=> nil
111
+ def delete(priority)
112
+ @heap.delete(priority)
113
+ end
114
+
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,72 @@
1
+ require 'containers/deque'
2
+
3
+ =begin rdoc
4
+ A Queue is a container that keeps elements in a first-in first-out (FIFO) order. Because of its
5
+ properties, it is often used as a buffer.
6
+
7
+ This implementation uses a doubly-linked list, guaranteeing O(1) complexity for all operations.
8
+
9
+ =end
10
+ module Algorithms
11
+ module Containers
12
+ class Queue
13
+ include Enumerable
14
+ # Create a new queue. Takes an optional array argument to initialize the queue.
15
+ #
16
+ # q = Algorithms::Containers::Queue.new([1, 2, 3])
17
+ # q.pop #=> 1
18
+ # q.pop #=> 2
19
+ def initialize(ary=[])
20
+ @container = Deque.new(ary)
21
+ end
22
+
23
+ # Returns the next item from the queue but does not remove it.
24
+ #
25
+ # q = Algorithms::Containers::Queue.new([1, 2, 3])
26
+ # q.next #=> 1
27
+ # q.size #=> 3
28
+ def next
29
+ @container.front
30
+ end
31
+
32
+ # Adds an item to the queue.
33
+ #
34
+ # q = Algorithms::Containers::Queue.new([1])
35
+ # q.push(2)
36
+ # q.pop #=> 1
37
+ # q.pop #=> 2
38
+ def push(obj)
39
+ @container.push_back(obj)
40
+ end
41
+ alias_method :<<, :push
42
+
43
+ # Removes the next item from the queue and returns it.
44
+ #
45
+ # q = Algorithms::Containers::Queue.new([1, 2, 3])
46
+ # q.pop #=> 1
47
+ # q.size #=> 2
48
+ def pop
49
+ @container.pop_front
50
+ end
51
+
52
+ # Return the number of items in the queue.
53
+ #
54
+ # q = Algorithms::Containers::Queue.new([1, 2, 3])
55
+ # q.size #=> 3
56
+ def size
57
+ @container.size
58
+ end
59
+
60
+ # Returns true if the queue is empty, false otherwise.
61
+ def empty?
62
+ @container.empty?
63
+ end
64
+
65
+ # Iterate over the Queue in FIFO order.
66
+ def each(&block)
67
+ @container.each_forward(&block)
68
+ end
69
+
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,402 @@
1
+ require 'containers/stack'
2
+ =begin rdoc
3
+ A RBTreeMap is a map that is stored in sorted order based on the order of its keys. This ordering is
4
+ determined by applying the function <=> to compare the keys. No duplicate values for keys are allowed,
5
+ so duplicate values are overwritten.
6
+
7
+ A major advantage of RBTreeMap over a Hash is the fact that keys are stored in order and can thus be
8
+ iterated over in order. This is useful for many datasets.
9
+
10
+ The implementation is adapted from Robert Sedgewick's Left Leaning Red-Black Tree implementation,
11
+ which can be found at http://www.cs.princeton.edu/~rs/talks/LLRB/Java/RedBlackBST.java
12
+
13
+ Algorithms::Containers::RBTreeMap automatically uses the faster C implementation if it was built
14
+ when the gem was installed. Alternatively, Algorithms::Containers::RubyRBTreeMap and Algorithms::Containers::CRBTreeMap can be
15
+ explicitly used as well; their functionality is identical.
16
+
17
+ Most methods have O(log n) complexity.
18
+
19
+ =end
20
+ module Algorithms
21
+ module Containers
22
+ class RubyRBTreeMap
23
+ include Enumerable
24
+
25
+ attr_accessor :height_black
26
+
27
+ # Create and initialize a new empty TreeMap.
28
+ def initialize
29
+ @root = nil
30
+ @height_black = 0
31
+ end
32
+
33
+ # Insert an item with an associated key into the TreeMap, and returns the item inserted
34
+ #
35
+ # Complexity: O(log n)
36
+ #
37
+ # map = Algorithms::Containers::TreeMap.new
38
+ # map.push("MA", "Massachusetts") #=> "Massachusetts"
39
+ # map.get("MA") #=> "Massachusetts"
40
+ def push(key, value)
41
+ @root = insert(@root, key, value)
42
+ @height_black += 1 if isred(@root)
43
+ @root.color = :black
44
+ value
45
+ end
46
+ alias_method :[]=, :push
47
+
48
+ # Return the number of items in the TreeMap.
49
+ #
50
+ # map = Algorithms::Containers::TreeMap.new
51
+ # map.push("MA", "Massachusetts")
52
+ # map.push("GA", "Georgia")
53
+ # map.size #=> 2
54
+ def size
55
+ @root and @root.size or 0
56
+ end
57
+
58
+ # Return the height of the tree structure in the TreeMap.
59
+ #
60
+ # Complexity: O(1)
61
+ #
62
+ # map = Algorithms::Containers::TreeMap.new
63
+ # map.push("MA", "Massachusetts")
64
+ # map.push("GA", "Georgia")
65
+ # map.height #=> 2
66
+ def height
67
+ @root and @root.height or 0
68
+ end
69
+
70
+ # Return true if key is found in the TreeMap, false otherwise
71
+ #
72
+ # Complexity: O(log n)
73
+ #
74
+ # map = Algorithms::Containers::TreeMap.new
75
+ # map.push("MA", "Massachusetts")
76
+ # map.push("GA", "Georgia")
77
+ # map.has_key?("GA") #=> true
78
+ # map.has_key?("DE") #=> false
79
+ def has_key?(key)
80
+ !get(key).nil?
81
+ end
82
+
83
+ # Return the item associated with the key, or nil if none found.
84
+ #
85
+ # Complexity: O(log n)
86
+ #
87
+ # map = Algorithms::Containers::TreeMap.new
88
+ # map.push("MA", "Massachusetts")
89
+ # map.push("GA", "Georgia")
90
+ # map.get("GA") #=> "Georgia"
91
+ def get(key)
92
+ get_recursive(@root, key)
93
+ end
94
+ alias_method :[], :get
95
+
96
+ # Return the smallest key in the map.
97
+ #
98
+ # Complexity: O(log n)
99
+ #
100
+ # map = Algorithms::Containers::TreeMap.new
101
+ # map.push("MA", "Massachusetts")
102
+ # map.push("GA", "Georgia")
103
+ # map.min_key #=> "GA"
104
+ def min_key
105
+ @root.nil? ? nil : min_recursive(@root)
106
+ end
107
+
108
+ # Return the largest key in the map.
109
+ #
110
+ # Complexity: O(log n)
111
+ #
112
+ # map = Algorithms::Containers::TreeMap.new
113
+ # map.push("MA", "Massachusetts")
114
+ # map.push("GA", "Georgia")
115
+ # map.max_key #=> "MA"
116
+ def max_key
117
+ @root.nil? ? nil : max_recursive(@root)
118
+ end
119
+
120
+ # Deletes the item and key if it's found, and returns the item. Returns nil
121
+ # if key is not present.
122
+ #
123
+ # !!! Warning !!! There is a currently a bug in the delete method that occurs rarely
124
+ # but often enough, especially in large datasets. It is currently under investigation.
125
+ #
126
+ # Complexity: O(log n)
127
+ #
128
+ # map = Algorithms::Containers::TreeMap.new
129
+ # map.push("MA", "Massachusetts")
130
+ # map.push("GA", "Georgia")
131
+ # map.min_key #=> "GA"
132
+ def delete(key)
133
+ result = nil
134
+ if @root
135
+ @root, result = delete_recursive(@root, key)
136
+ @root.color = :black if @root
137
+ end
138
+ result
139
+ end
140
+
141
+ # Returns true if the tree is empty, false otherwise
142
+ def empty?
143
+ @root.nil?
144
+ end
145
+
146
+ # Deletes the item with the smallest key and returns the item. Returns nil
147
+ # if key is not present.
148
+ #
149
+ # Complexity: O(log n)
150
+ #
151
+ # map = Algorithms::Containers::TreeMap.new
152
+ # map.push("MA", "Massachusetts")
153
+ # map.push("GA", "Georgia")
154
+ # map.delete_min #=> "Massachusetts"
155
+ # map.size #=> 1
156
+ def delete_min
157
+ result = nil
158
+ if @root
159
+ @root, result = delete_min_recursive(@root)
160
+ @root.color = :black if @root
161
+ end
162
+ result
163
+ end
164
+
165
+ # Deletes the item with the smallest key and returns the item. Returns nil
166
+ # if key is not present.
167
+ #
168
+ # Complexity: O(log n)
169
+ #
170
+ # map = Algorithms::Containers::TreeMap.new
171
+ # map.push("MA", "Massachusetts")
172
+ # map.push("GA", "Georgia")
173
+ # map.delete_max #=> "Georgia"
174
+ # map.size #=> 1
175
+ def delete_max
176
+ result = nil
177
+ if @root
178
+ @root, result = delete_max_recursive(@root)
179
+ @root.color = :black if @root
180
+ end
181
+ result
182
+ end
183
+
184
+ # Iterates over the TreeMap from smallest to largest element. Iterative approach.
185
+ def each
186
+ return nil unless @root
187
+ stack = Stack.new
188
+ cursor = @root
189
+ loop do
190
+ if cursor
191
+ stack.push(cursor)
192
+ cursor = cursor.left
193
+ else
194
+ unless stack.empty?
195
+ cursor = stack.pop
196
+ yield(cursor.key, cursor.value)
197
+ cursor = cursor.right
198
+ else
199
+ break
200
+ end
201
+ end
202
+ end
203
+ end
204
+
205
+ class Node # :nodoc: all
206
+ attr_accessor :color, :key, :value, :left, :right, :size, :height
207
+ def initialize(key, value)
208
+ @key = key
209
+ @value = value
210
+ @color = :red
211
+ @left = nil
212
+ @right = nil
213
+ @size = 1
214
+ @height = 1
215
+ end
216
+
217
+ def red?
218
+ @color == :red
219
+ end
220
+
221
+ def colorflip
222
+ @color = @color == :red ? :black : :red
223
+ @left.color = @left.color == :red ? :black : :red
224
+ @right.color = @right.color == :red ? :black : :red
225
+ end
226
+
227
+ def update_size
228
+ @size = (@left ? @left.size : 0) + (@right ? @right.size : 0) + 1
229
+ left_height = (@left ? @left.height : 0)
230
+ right_height = (@right ? @right.height : 0)
231
+ if left_height > right_height
232
+ @height = left_height + 1
233
+ else
234
+ @height = right_height + 1
235
+ end
236
+ self
237
+ end
238
+
239
+ def rotate_left
240
+ r = @right
241
+ r_key, r_value, r_color = r.key, r.value, r.color
242
+ b = r.left
243
+ r.left = @left
244
+ @left = r
245
+ @right = r.right
246
+ r.right = b
247
+ r.color, r.key, r.value = :red, @key, @value
248
+ @key, @value = r_key, r_value
249
+ r.update_size
250
+ update_size
251
+ end
252
+
253
+ def rotate_right
254
+ l = @left
255
+ l_key, l_value, l_color = l.key, l.value, l.color
256
+ b = l.right
257
+ l.right = @right
258
+ @right = l
259
+ @left = l.left
260
+ l.left = b
261
+ l.color, l.key, l.value = :red, @key, @value
262
+ @key, @value = l_key, l_value
263
+ l.update_size
264
+ update_size
265
+ end
266
+
267
+ def move_red_left
268
+ colorflip
269
+ if (@right.left && @right.left.red?)
270
+ @right.rotate_right
271
+ rotate_left
272
+ colorflip
273
+ end
274
+ self
275
+ end
276
+
277
+ def move_red_right
278
+ colorflip
279
+ if (@left.left && @left.left.red?)
280
+ rotate_right
281
+ colorflip
282
+ end
283
+ self
284
+ end
285
+
286
+ def fixup
287
+ rotate_left if @right && @right.red?
288
+ rotate_right if (@left && @left.red?) && (@left.left && @left.left.red?)
289
+ colorflip if (@left && @left.red?) && (@right && @right.red?)
290
+
291
+ update_size
292
+ end
293
+ end
294
+
295
+ def delete_recursive(node, key)
296
+ if (key <=> node.key) == -1
297
+ node.move_red_left if ( !isred(node.left) && !isred(node.left.left) )
298
+ node.left, result = delete_recursive(node.left, key)
299
+ else
300
+ node.rotate_right if isred(node.left)
301
+ if ( ( (key <=> node.key) == 0) && node.right.nil? )
302
+ return nil, node.value
303
+ end
304
+ if ( !isred(node.right) && !isred(node.right.left) )
305
+ node.move_red_right
306
+ end
307
+ if (key <=> node.key) == 0
308
+ result = node.value
309
+ node.value = get_recursive(node.right, min_recursive(node.right))
310
+ node.key = min_recursive(node.right)
311
+ node.right = delete_min_recursive(node.right).first
312
+ else
313
+ node.right, result = delete_recursive(node.right, key)
314
+ end
315
+ end
316
+ return node.fixup, result
317
+ end
318
+ private :delete_recursive
319
+
320
+ def delete_min_recursive(node)
321
+ if node.left.nil?
322
+ return nil, node.value
323
+ end
324
+ if ( !isred(node.left) && !isred(node.left.left) )
325
+ node.move_red_left
326
+ end
327
+ node.left, result = delete_min_recursive(node.left)
328
+
329
+ return node.fixup, result
330
+ end
331
+ private :delete_min_recursive
332
+
333
+ def delete_max_recursive(node)
334
+ if (isred(node.left))
335
+ node = node.rotate_right
336
+ end
337
+ return nil, node.value if node.right.nil?
338
+ if ( !isred(node.right) && !isred(node.right.left) )
339
+ node.move_red_right
340
+ end
341
+ node.right, result = delete_max_recursive(node.right)
342
+
343
+ return node.fixup, result
344
+ end
345
+ private :delete_max_recursive
346
+
347
+ def get_recursive(node, key)
348
+ return nil if node.nil?
349
+ case key <=> node.key
350
+ when 0 then return node.value
351
+ when -1 then return get_recursive(node.left, key)
352
+ when 1 then return get_recursive(node.right, key)
353
+ end
354
+ end
355
+ private :get_recursive
356
+
357
+ def min_recursive(node)
358
+ return node.key if node.left.nil?
359
+
360
+ min_recursive(node.left)
361
+ end
362
+ private :min_recursive
363
+
364
+ def max_recursive(node)
365
+ return node.key if node.right.nil?
366
+
367
+ max_recursive(node.right)
368
+ end
369
+ private :max_recursive
370
+
371
+ def insert(node, key, value)
372
+ return Node.new(key, value) unless node
373
+
374
+ case key <=> node.key
375
+ when 0 then node.value = value
376
+ when -1 then node.left = insert(node.left, key, value)
377
+ when 1 then node.right = insert(node.right, key, value)
378
+ end
379
+
380
+ node.rotate_left if (node.right && node.right.red?)
381
+ node.rotate_right if (node.left && node.left.red? && node.left.left && node.left.left.red?)
382
+ node.colorflip if (node.left && node.left.red? && node.right && node.right.red?)
383
+ node.update_size
384
+ end
385
+ private :insert
386
+
387
+ def isred(node)
388
+ return false if node.nil?
389
+
390
+ node.color == :red
391
+ end
392
+ private :isred
393
+ end
394
+ end
395
+
396
+ begin
397
+ require 'CRBTreeMap'
398
+ Containers::RBTreeMap = Containers::CRBTreeMap
399
+ rescue LoadError # C Version could not be found, try ruby version
400
+ Containers::RBTreeMap = Containers::RubyRBTreeMap
401
+ end
402
+ end