algorithms 0.0.1 → 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.
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