algorithms 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/History.txt +139 -2
  2. data/Manifest +31 -8
  3. data/README +90 -0
  4. data/Rakefile +22 -9
  5. data/algorithms.gemspec +28 -101
  6. data/benchmark.rb +29 -27
  7. data/benchmarks/rbench.rb +16 -0
  8. data/benchmarks/rbench/column.rb +26 -0
  9. data/benchmarks/rbench/group.rb +43 -0
  10. data/benchmarks/rbench/report.rb +53 -0
  11. data/benchmarks/rbench/runner.rb +109 -0
  12. data/benchmarks/rbench/summary.rb +51 -0
  13. data/benchmarks/sorts.rb +33 -0
  14. data/ext/containers/bst/bst.c +205 -0
  15. data/ext/containers/{priority_queue → bst}/extconf.rb +1 -1
  16. data/ext/containers/deque/deque.c +233 -0
  17. data/ext/containers/deque/extconf.rb +4 -0
  18. data/ext/containers/tree_map/extconf.rb +1 -1
  19. data/ext/containers/tree_map/rbtree.c +73 -25
  20. data/lib/algorithms.rb +65 -6
  21. data/lib/algorithms/search.rb +84 -0
  22. data/lib/algorithms/sort.rb +238 -0
  23. data/lib/containers/deque.rb +176 -0
  24. data/lib/containers/heap.rb +451 -111
  25. data/lib/containers/kd_tree.rb +87 -0
  26. data/lib/containers/priority_queue.rb +107 -508
  27. data/lib/containers/queue.rb +62 -23
  28. data/lib/containers/rb_tree_map.rb +398 -0
  29. data/lib/containers/splay_tree_map.rb +274 -0
  30. data/lib/containers/stack.rb +59 -21
  31. data/lib/containers/suffix_array.rb +68 -0
  32. data/lib/containers/trie.rb +182 -0
  33. data/lib/graphs/graph.rb +25 -0
  34. data/spec/bst_spec.rb +31 -0
  35. data/spec/deque_spec.rb +108 -0
  36. data/spec/heap_spec.rb +111 -66
  37. data/spec/kd_tree_spec.rb +89 -0
  38. data/spec/priority_queue_spec.rb +71 -27
  39. data/spec/queue_spec.rb +53 -45
  40. data/spec/rb_tree_map_spec.rb +123 -0
  41. data/spec/search_spec.rb +28 -0
  42. data/spec/sort_spec.rb +28 -0
  43. data/spec/splay_tree_map_spec.rb +102 -0
  44. data/spec/stack_spec.rb +56 -49
  45. data/spec/suffix_array_spec.rb +40 -0
  46. data/spec/trie_spec.rb +59 -0
  47. metadata +54 -32
  48. data/README.txt +0 -58
  49. data/ext/containers/priority_queue/priority_queue.c +0 -948
  50. data/ext/containers/tree_map/Rakefile +0 -4
  51. data/lib/containers/hash.rb +0 -0
  52. data/lib/containers/tree_map.rb +0 -265
  53. data/spec/priority_queue_test.rb +0 -371
  54. data/spec/tree_map_spec.rb +0 -99
@@ -1,29 +1,68 @@
1
- module Containers
2
- # Use a Ruby array for storage
3
- class Queue
4
- def initialize(ary=[])
5
- @container = ary
6
- end
7
-
8
- def put(object)
9
- @container.push(object)
10
- end
11
-
12
- def peek
13
- @container[0]
14
- end
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.
15
8
 
16
- def get
17
- @container.shift
18
- end
9
+ =end
10
+ class Containers::Queue
11
+ include Enumerable
12
+ # Create a new queue. Takes an optional array argument to initialize the queue.
13
+ #
14
+ # q = Containers::Queue.new([1, 2, 3])
15
+ # q.pop #=> 1
16
+ # q.pop #=> 2
17
+ def initialize(ary=[])
18
+ @container = Containers::Deque.new(ary)
19
+ end
20
+
21
+ # Returns the next item from the queue but does not remove it.
22
+ #
23
+ # q = Containers::Queue.new([1, 2, 3])
24
+ # q.next #=> 1
25
+ # q.size #=> 3
26
+ def next
27
+ @container.front
28
+ end
29
+
30
+ # Adds an item to the queue.
31
+ #
32
+ # q = Containers::Queue.new([1])
33
+ # q.push(2)
34
+ # q.pop #=> 1
35
+ # q.pop #=> 2
36
+ def push(obj)
37
+ @container.push_back(obj)
38
+ end
39
+ alias_method :<<, :push
19
40
 
20
- def size
21
- @container.size
22
- end
41
+ # Removes the next item from the queue and returns it.
42
+ #
43
+ # q = Containers::Queue.new([1, 2, 3])
44
+ # q.pop #=> 1
45
+ # q.size #=> 2
46
+ def pop
47
+ @container.pop_front
48
+ end
23
49
 
24
- def empty?
25
- @container.empty?
26
- end
50
+ # Return the number of items in the queue.
51
+ #
52
+ # q = Containers::Queue.new([1, 2, 3])
53
+ # q.size #=> 3
54
+ def size
55
+ @container.size
56
+ end
57
+
58
+ # Returns true if the queue is empty, false otherwise.
59
+ def empty?
60
+ @container.empty?
61
+ end
27
62
 
63
+ # Iterate over the Queue in FIFO order.
64
+ def each(&block)
65
+ @container.each_forward(&block)
28
66
  end
67
+
29
68
  end
@@ -0,0 +1,398 @@
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
+ Containers::RBTreeMap automatically uses the faster C implementation if it was built
14
+ when the gem was installed. Alternatively, Containers::RubyRBTreeMap and 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
+ class Containers::RubyRBTreeMap
21
+ include Enumerable
22
+
23
+ attr_accessor :height_black
24
+
25
+ # Create and initialize a new empty TreeMap.
26
+ def initialize
27
+ @root = nil
28
+ @height_black = 0
29
+ end
30
+
31
+ # Insert an item with an associated key into the TreeMap, and returns the item inserted
32
+ #
33
+ # Complexity: O(log n)
34
+ #
35
+ # map = Containers::TreeMap.new
36
+ # map.push("MA", "Massachusetts") #=> "Massachusetts"
37
+ # map.get("MA") #=> "Massachusetts"
38
+ def push(key, value)
39
+ @root = insert(@root, key, value)
40
+ @height_black += 1 if isred(@root)
41
+ @root.color = :black
42
+ value
43
+ end
44
+ alias_method :[]=, :push
45
+
46
+ # Return the number of items in the TreeMap.
47
+ #
48
+ # map = Containers::TreeMap.new
49
+ # map.push("MA", "Massachusetts")
50
+ # map.push("GA", "Georgia")
51
+ # map.size #=> 2
52
+ def size
53
+ @root and @root.size or 0
54
+ end
55
+
56
+ # Return the height of the tree structure in the TreeMap.
57
+ #
58
+ # Complexity: O(1)
59
+ #
60
+ # map = Containers::TreeMap.new
61
+ # map.push("MA", "Massachusetts")
62
+ # map.push("GA", "Georgia")
63
+ # map.height #=> 2
64
+ def height
65
+ @root and @root.height or 0
66
+ end
67
+
68
+ # Return true if key is found in the TreeMap, false otherwise
69
+ #
70
+ # Complexity: O(log n)
71
+ #
72
+ # map = Containers::TreeMap.new
73
+ # map.push("MA", "Massachusetts")
74
+ # map.push("GA", "Georgia")
75
+ # map.has_key?("GA") #=> true
76
+ # map.has_key?("DE") #=> false
77
+ def has_key?(key)
78
+ !get(key).nil?
79
+ end
80
+
81
+ # Return the item associated with the key, or nil if none found.
82
+ #
83
+ # Complexity: O(log n)
84
+ #
85
+ # map = Containers::TreeMap.new
86
+ # map.push("MA", "Massachusetts")
87
+ # map.push("GA", "Georgia")
88
+ # map.get("GA") #=> "Georgia"
89
+ def get(key)
90
+ get_recursive(@root, key)
91
+ end
92
+ alias_method :[], :get
93
+
94
+ # Return the smallest key in the map.
95
+ #
96
+ # Complexity: O(log n)
97
+ #
98
+ # map = Containers::TreeMap.new
99
+ # map.push("MA", "Massachusetts")
100
+ # map.push("GA", "Georgia")
101
+ # map.min_key #=> "GA"
102
+ def min_key
103
+ @root.nil? ? nil : min_recursive(@root)
104
+ end
105
+
106
+ # Return the largest key in the map.
107
+ #
108
+ # Complexity: O(log n)
109
+ #
110
+ # map = Containers::TreeMap.new
111
+ # map.push("MA", "Massachusetts")
112
+ # map.push("GA", "Georgia")
113
+ # map.max_key #=> "MA"
114
+ def max_key
115
+ @root.nil? ? nil : max_recursive(@root)
116
+ end
117
+
118
+ # Deletes the item and key if it's found, and returns the item. Returns nil
119
+ # if key is not present.
120
+ #
121
+ # !!! Warning !!! There is a currently a bug in the delete method that occurs rarely
122
+ # but often enough, especially in large datasets. It is currently under investigation.
123
+ #
124
+ # Complexity: O(log n)
125
+ #
126
+ # map = Containers::TreeMap.new
127
+ # map.push("MA", "Massachusetts")
128
+ # map.push("GA", "Georgia")
129
+ # map.min_key #=> "GA"
130
+ def delete(key)
131
+ result = nil
132
+ if @root
133
+ @root, result = delete_recursive(@root, key)
134
+ @root.color = :black if @root
135
+ end
136
+ result
137
+ end
138
+
139
+ # Returns true if the tree is empty, false otherwise
140
+ def empty?
141
+ @root.nil?
142
+ end
143
+
144
+ # Deletes the item with the smallest key and returns the item. Returns nil
145
+ # if key is not present.
146
+ #
147
+ # Complexity: O(log n)
148
+ #
149
+ # map = Containers::TreeMap.new
150
+ # map.push("MA", "Massachusetts")
151
+ # map.push("GA", "Georgia")
152
+ # map.delete_min #=> "Massachusetts"
153
+ # map.size #=> 1
154
+ def delete_min
155
+ result = nil
156
+ if @root
157
+ @root, result = delete_min_recursive(@root)
158
+ @root.color = :black if @root
159
+ end
160
+ result
161
+ end
162
+
163
+ # Deletes the item with the smallest key and returns the item. Returns nil
164
+ # if key is not present.
165
+ #
166
+ # Complexity: O(log n)
167
+ #
168
+ # map = Containers::TreeMap.new
169
+ # map.push("MA", "Massachusetts")
170
+ # map.push("GA", "Georgia")
171
+ # map.delete_max #=> "Georgia"
172
+ # map.size #=> 1
173
+ def delete_max
174
+ result = nil
175
+ if @root
176
+ @root, result = delete_max_recursive(@root)
177
+ @root.color = :black if @root
178
+ end
179
+ result
180
+ end
181
+
182
+ # Iterates over the TreeMap from smallest to largest element. Iterative approach.
183
+ def each
184
+ return nil unless @root
185
+ stack = Containers::Stack.new
186
+ cursor = @root
187
+ loop do
188
+ if cursor
189
+ stack.push(cursor)
190
+ cursor = cursor.left
191
+ else
192
+ unless stack.empty?
193
+ cursor = stack.pop
194
+ yield(cursor.key, cursor.value)
195
+ cursor = cursor.right
196
+ else
197
+ break
198
+ end
199
+ end
200
+ end
201
+ end
202
+
203
+ class Node # :nodoc: all
204
+ attr_accessor :color, :key, :value, :left, :right, :size, :height
205
+ def initialize(key, value)
206
+ @key = key
207
+ @value = value
208
+ @color = :red
209
+ @left = nil
210
+ @right = nil
211
+ @size = 1
212
+ @height = 1
213
+ end
214
+
215
+ def red?
216
+ @color == :red
217
+ end
218
+
219
+ def colorflip
220
+ @color = @color == :red ? :black : :red
221
+ @left.color = @left.color == :red ? :black : :red
222
+ @right.color = @right.color == :red ? :black : :red
223
+ end
224
+
225
+ def update_size
226
+ @size = (@left ? @left.size : 0) + (@right ? @right.size : 0) + 1
227
+ left_height = (@left ? @left.height : 0)
228
+ right_height = (@right ? @right.height : 0)
229
+ if left_height > right_height
230
+ @height = left_height + 1
231
+ else
232
+ @height = right_height + 1
233
+ end
234
+ self
235
+ end
236
+
237
+ def rotate_left
238
+ r = @right
239
+ r_key, r_value, r_color = r.key, r.value, r.color
240
+ b = r.left
241
+ r.left = @left
242
+ @left = r
243
+ @right = r.right
244
+ r.right = b
245
+ r.color, r.key, r.value = :red, @key, @value
246
+ @key, @value = r_key, r_value
247
+ r.update_size
248
+ update_size
249
+ end
250
+
251
+ def rotate_right
252
+ l = @left
253
+ l_key, l_value, l_color = l.key, l.value, l.color
254
+ b = l.right
255
+ l.right = @right
256
+ @right = l
257
+ @left = l.left
258
+ l.left = b
259
+ l.color, l.key, l.value = :red, @key, @value
260
+ @key, @value = l_key, l_value
261
+ l.update_size
262
+ update_size
263
+ end
264
+
265
+ def move_red_left
266
+ colorflip
267
+ if (@right.left && @right.left.red?)
268
+ @right.rotate_right
269
+ rotate_left
270
+ colorflip
271
+ end
272
+ self
273
+ end
274
+
275
+ def move_red_right
276
+ colorflip
277
+ if (@left.left && @left.left.red?)
278
+ rotate_right
279
+ colorflip
280
+ end
281
+ self
282
+ end
283
+
284
+ def fixup
285
+ rotate_left if @right && @right.red?
286
+ rotate_right if (@left && @left.red?) && (@left.left && @left.left.red?)
287
+ colorflip if (@left && @left.red?) && (@right && @right.red?)
288
+
289
+ update_size
290
+ end
291
+ end
292
+
293
+ def delete_recursive(node, key)
294
+ if (key <=> node.key) == -1
295
+ node.move_red_left if ( !isred(node.left) && !isred(node.left.left) )
296
+ node.left, result = delete_recursive(node.left, key)
297
+ else
298
+ node.rotate_right if isred(node.left)
299
+ if ( ( (key <=> node.key) == 0) && node.right.nil? )
300
+ return nil, node.value
301
+ end
302
+ if ( !isred(node.right) && !isred(node.right.left) )
303
+ node.move_red_right
304
+ end
305
+ if (key <=> node.key) == 0
306
+ result = node.value
307
+ node.value = get_recursive(node.right, min_recursive(node.right))
308
+ node.key = min_recursive(node.right)
309
+ node.right = delete_min_recursive(node.right).first
310
+ else
311
+ node.right, result = delete_recursive(node.right, key)
312
+ end
313
+ end
314
+ return node.fixup, result
315
+ end
316
+ private :delete_recursive
317
+
318
+ def delete_min_recursive(node)
319
+ if node.left.nil?
320
+ return nil, node.value
321
+ end
322
+ if ( !isred(node.left) && !isred(node.left.left) )
323
+ node.move_red_left
324
+ end
325
+ node.left, result = delete_min_recursive(node.left)
326
+
327
+ return node.fixup, result
328
+ end
329
+ private :delete_min_recursive
330
+
331
+ def delete_max_recursive(node)
332
+ if (isred(node.left))
333
+ node = node.rotate_right
334
+ end
335
+ return nil, node.value if node.right.nil?
336
+ if ( !isred(node.right) && !isred(node.right.left) )
337
+ node.move_red_right
338
+ end
339
+ node.right, result = delete_max_recursive(node.right)
340
+
341
+ return node.fixup, result
342
+ end
343
+ private :delete_max_recursive
344
+
345
+ def get_recursive(node, key)
346
+ return nil if node.nil?
347
+ case key <=> node.key
348
+ when 0 then return node.value
349
+ when -1 then return get_recursive(node.left, key)
350
+ when 1 then return get_recursive(node.right, key)
351
+ end
352
+ end
353
+ private :get_recursive
354
+
355
+ def min_recursive(node)
356
+ return node.key if node.left.nil?
357
+
358
+ min_recursive(node.left)
359
+ end
360
+ private :min_recursive
361
+
362
+ def max_recursive(node)
363
+ return node.key if node.right.nil?
364
+
365
+ max_recursive(node.right)
366
+ end
367
+ private :max_recursive
368
+
369
+ def insert(node, key, value)
370
+ return Node.new(key, value) unless node
371
+
372
+ case key <=> node.key
373
+ when 0 then node.value = value
374
+ when -1 then node.left = insert(node.left, key, value)
375
+ when 1 then node.right = insert(node.right, key, value)
376
+ end
377
+
378
+ node.rotate_left if (node.right && node.right.red?)
379
+ node.rotate_right if (node.left && node.left.red? && node.left.left && node.left.left.red?)
380
+ node.colorflip if (node.left && node.left.red? && node.right && node.right.red?)
381
+ node.update_size
382
+ end
383
+ private :insert
384
+
385
+ def isred(node)
386
+ return false if node.nil?
387
+
388
+ node.color == :red
389
+ end
390
+ private :isred
391
+ end
392
+
393
+ begin
394
+ require 'CRBTreeMap'
395
+ Containers::RBTreeMap = Containers::CRBTreeMap
396
+ rescue LoadError # C Version could not be found, try ruby version
397
+ Containers::RBTreeMap = Containers::RubyRBTreeMap
398
+ end