grosser-algorithms 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data/History.txt +176 -0
  2. data/Manifest +47 -0
  3. data/README.markdown +102 -0
  4. data/Rakefile +26 -0
  5. data/algorithms.gemspec +32 -0
  6. data/benchmarks/deque.rb +18 -0
  7. data/benchmarks/sorts.rb +34 -0
  8. data/benchmarks/treemaps.rb +52 -0
  9. data/ext/algorithms/string/extconf.rb +4 -0
  10. data/ext/algorithms/string/string.c +70 -0
  11. data/ext/containers/deque/deque.c +249 -0
  12. data/ext/containers/deque/extconf.rb +4 -0
  13. data/ext/containers/rbtree_map/extconf.rb +4 -0
  14. data/ext/containers/rbtree_map/rbtree.c +500 -0
  15. data/ext/containers/splaytree_map/extconf.rb +4 -0
  16. data/ext/containers/splaytree_map/splaytree.c +421 -0
  17. data/grosser-algorithms.gemspec +31 -0
  18. data/lib/algorithms.rb +71 -0
  19. data/lib/algorithms/search.rb +86 -0
  20. data/lib/algorithms/sort.rb +243 -0
  21. data/lib/algorithms/string.rb +8 -0
  22. data/lib/containers/deque.rb +176 -0
  23. data/lib/containers/heap.rb +507 -0
  24. data/lib/containers/kd_tree.rb +113 -0
  25. data/lib/containers/priority_queue.rb +117 -0
  26. data/lib/containers/queue.rb +72 -0
  27. data/lib/containers/rb_tree_map.rb +402 -0
  28. data/lib/containers/splay_tree_map.rb +273 -0
  29. data/lib/containers/stack.rb +71 -0
  30. data/lib/containers/suffix_array.rb +72 -0
  31. data/lib/containers/trie.rb +188 -0
  32. data/spec/deque_gc_mark_spec.rb +18 -0
  33. data/spec/deque_spec.rb +108 -0
  34. data/spec/heap_spec.rb +126 -0
  35. data/spec/kd_expected_out.txt +10000 -0
  36. data/spec/kd_test_in.txt +10000 -0
  37. data/spec/kd_tree_spec.rb +34 -0
  38. data/spec/map_gc_mark_spec.rb +29 -0
  39. data/spec/priority_queue_spec.rb +75 -0
  40. data/spec/queue_spec.rb +61 -0
  41. data/spec/rb_tree_map_spec.rb +122 -0
  42. data/spec/search_spec.rb +28 -0
  43. data/spec/sort_spec.rb +27 -0
  44. data/spec/splay_tree_map_spec.rb +106 -0
  45. data/spec/stack_spec.rb +60 -0
  46. data/spec/string_spec.rb +13 -0
  47. data/spec/suffix_array_spec.rb +40 -0
  48. data/spec/trie_spec.rb +59 -0
  49. metadata +141 -0
@@ -0,0 +1,507 @@
1
+ =begin rdoc
2
+ A Heap is a container that satisfies the heap property that nodes are
3
+ always smaller in value than their parent node.
4
+
5
+ The Algorithms::Containers::Heap class is flexible and upon
6
+ initialization, takes an optional block that determines how the items are
7
+ ordered. Two versions that are included are the
8
+ Algorithms::Containers::MaxHeap and Algorithms::Containers::MinHeap that
9
+ return the largest and smallest items on each invocation, respectively.
10
+
11
+ This library implements a Fibonacci heap, which allows O(1) complexity for
12
+ most methods.
13
+ =end
14
+ module Algorithms
15
+ module Containers
16
+ class Heap
17
+ include Enumerable
18
+
19
+ # call-seq:
20
+ # size -> int
21
+ #
22
+ # Return the number of elements in the heap.
23
+ def size
24
+ @size
25
+ end
26
+ alias_method :length, :size
27
+
28
+ # call-seq:
29
+ # Heap.new(optional_array) { |x, y| optional_comparison_fn }
30
+ # -> new_heap
31
+ #
32
+ # If an optional array is passed, the entries in the array are inserted
33
+ # into the heap with equal key and value fields. Also, an optional block
34
+ # can be passed to define the function that maintains heap property. For
35
+ # example, a min-heap can be created with:
36
+ #
37
+ # minheap = Heap.new { |x, y| (x <=> y) == -1 }
38
+ # minheap.push(6)
39
+ # minheap.push(10)
40
+ # minheap.pop #=> 6
41
+ #
42
+ # Thus, smaller elements will be parent nodes. The heap defaults to a
43
+ # min-heap if no block is given.
44
+ def initialize(ary=[], &block)
45
+ @compare_fn = block || lambda { |x, y| (x <=> y) == -1 }
46
+ @next = nil
47
+ @size = 0
48
+ @stored = {}
49
+
50
+ ary.each { |n| push(n) } unless ary.empty?
51
+ end
52
+
53
+ # call-seq:
54
+ # push(key, value) -> value
55
+ # push(value) -> value
56
+ #
57
+ # Inserts an item with a given key into the heap. If only one parameter
58
+ # is given, the key is set to the value.
59
+ #
60
+ # Complexity: O(1)
61
+ #
62
+ # heap = MinHeap.new
63
+ # heap.push(1, "Cat")
64
+ # heap.push(2)
65
+ # heap.pop #=> "Cat"
66
+ # heap.pop #=> 2
67
+ def push(key, value=key)
68
+ raise ArgumentError, "Heap keys must not be nil." unless key
69
+ node = Node.new(key, value)
70
+ # Add new node to the left of the @next node
71
+ if @next
72
+ node.right = @next
73
+ node.left = @next.left
74
+ node.left.right = node
75
+ @next.left = node
76
+ if @compare_fn[key, @next.key]
77
+ @next = node
78
+ end
79
+ else
80
+ @next = node
81
+ end
82
+ @size += 1
83
+
84
+ arr = []
85
+ w = @next.right
86
+ until w == @next do
87
+ arr << w.value
88
+ w = w.right
89
+ end
90
+ arr << @next.value
91
+ @stored[key] ||= []
92
+ @stored[key] << node
93
+ value
94
+ end
95
+ alias_method :<<, :push
96
+
97
+ # call-seq:
98
+ # has_key?(key) -> true or false
99
+ #
100
+ # Returns true if heap contains the key.
101
+ #
102
+ # Complexity: O(1)
103
+ #
104
+ # minheap = MinHeap.new([1, 2])
105
+ # minheap.has_key?(2) #=> true
106
+ # minheap.has_key?(4) #=> false
107
+ def has_key?(key)
108
+ @stored[key] && !@stored[key].empty? ? true : false
109
+ end
110
+
111
+ # call-seq:
112
+ # next -> value
113
+ # next -> nil
114
+ #
115
+ # Returns the value of the next item in heap order, but does not remove
116
+ # it.
117
+ #
118
+ # Complexity: O(1)
119
+ #
120
+ # minheap = MinHeap.new([1, 2])
121
+ # minheap.next #=> 1
122
+ # minheap.size #=> 2
123
+ def next
124
+ @next && @next.value
125
+ end
126
+
127
+ # call-seq:
128
+ # clear -> nil
129
+ #
130
+ # Removes all elements from the heap, destructively.
131
+ #
132
+ # Complexity: O(1)
133
+ #
134
+ def clear
135
+ @next = nil
136
+ @size = 0
137
+ @stored = {}
138
+ nil
139
+ end
140
+
141
+ # call-seq:
142
+ # empty? -> true or false
143
+ #
144
+ # Returns true if the heap is empty, false otherwise.
145
+ def empty?
146
+ @next.nil?
147
+ end
148
+
149
+ # call-seq:
150
+ # merge!(otherheap) -> merged_heap
151
+ #
152
+ # Does a shallow merge of all the nodes in the other heap.
153
+ #
154
+ # Complexity: O(1)
155
+ #
156
+ # heap = MinHeap.new([5, 6, 7, 8])
157
+ # otherheap = MinHeap.new([1, 2, 3, 4])
158
+ # heap.merge!(otherheap)
159
+ # heap.size #=> 8
160
+ # heap.pop #=> 1
161
+ def merge!(otherheap)
162
+ raise ArgumentError, "Trying to merge a heap with something not a heap" unless otherheap.kind_of? Heap
163
+ other_root = otherheap.instance_variable_get("@next")
164
+ if other_root
165
+ @stored = @stored.merge(otherheap.instance_variable_get("@stored")) { |key, a, b| (a << b).flatten }
166
+ # Insert othernode's @next node to the left of current @next
167
+ @next.left.right = other_root
168
+ ol = other_root.left
169
+ other_root.left = @next.left
170
+ ol.right = @next
171
+ @next.left = ol
172
+
173
+ @next = other_root if @compare_fn[other_root.key, @next.key]
174
+ end
175
+ @size += otherheap.size
176
+ end
177
+
178
+ # call-seq:
179
+ # pop -> value
180
+ # pop -> nil
181
+ #
182
+ # Returns the value of the next item in heap order and removes it from
183
+ # the heap.
184
+ #
185
+ # Complexity: O(1)
186
+ #
187
+ # minheap = MinHeap.new([1, 2])
188
+ # minheap.pop #=> 1
189
+ # minheap.size #=> 1
190
+ def pop
191
+ return nil unless @next
192
+ popped = @next
193
+ if @size == 1
194
+ clear
195
+ return popped.value
196
+ end
197
+ # Merge the popped's children into root node
198
+ if @next.child
199
+ @next.child.parent = nil
200
+
201
+ # get rid of parent
202
+ sibling = @next.child.right
203
+ until sibling == @next.child
204
+ sibling.parent = nil
205
+ sibling = sibling.right
206
+ end
207
+
208
+ # Merge the children into the root. If @next is the only root node,
209
+ # make its child the @next node
210
+ if @next.right == @next
211
+ @next = @next.child
212
+ else
213
+ next_left, next_right = @next.left, @next.right
214
+ current_child = @next.child
215
+ @next.right.left = current_child
216
+ @next.left.right = current_child.right
217
+ current_child.right.left = next_left
218
+ current_child.right = next_right
219
+ @next = @next.right
220
+ end
221
+ else
222
+ @next.left.right = @next.right
223
+ @next.right.left = @next.left
224
+ @next = @next.right
225
+ end
226
+ consolidate
227
+
228
+ unless @stored[popped.key].delete(popped)
229
+ raise "Couldn't delete node from stored nodes hash"
230
+ end
231
+ @size -= 1
232
+
233
+ popped.value
234
+ end
235
+ alias_method :next!, :pop
236
+
237
+ # call-seq:
238
+ # change_key(key, new_key) -> [new_key, value]
239
+ # change_key(key, new_key) -> nil
240
+ #
241
+ # Changes the key from one to another. Doing so must not violate the
242
+ # heap property or an exception will be raised. If the key is found, an
243
+ # array containing the new key and value pair is returned, otherwise
244
+ # nil is returned.
245
+ #
246
+ # In the case of duplicate keys, an arbitrary key is changed. This will
247
+ # be investigated more in the future.
248
+ #
249
+ # Complexity: amortized O(1)
250
+ #
251
+ # minheap = MinHeap.new([1, 2])
252
+ # minheap.change_key(2, 3) #=> raise error since we can't increase the value in a min-heap
253
+ # minheap.change_key(2, 0) #=> [0, 2]
254
+ # minheap.pop #=> 2
255
+ # minheap.pop #=> 1
256
+ def change_key(key, new_key, delete=false)
257
+ return if @stored[key].nil? || @stored[key].empty? || (key == new_key)
258
+
259
+ # Must maintain heap property
260
+ raise "Changing this key would not maintain heap property!" unless (delete || @compare_fn[new_key, key])
261
+ node = @stored[key].shift
262
+ if node
263
+ node.key = new_key
264
+ @stored[new_key] ||= []
265
+ @stored[new_key] << node
266
+ parent = node.parent
267
+ if parent
268
+ # if heap property is violated
269
+ if delete || @compare_fn[new_key, parent.key]
270
+ cut(node, parent)
271
+ cascading_cut(parent)
272
+ end
273
+ end
274
+ if delete || @compare_fn[node.key, @next.key]
275
+ @next = node
276
+ end
277
+ return [node.key, node.value]
278
+ end
279
+ nil
280
+ end
281
+
282
+ # call-seq:
283
+ # delete(key) -> value
284
+ # delete(key) -> nil
285
+ #
286
+ # Deletes the item with associated key and returns it. nil is returned
287
+ # if the keyis not found. In the case of nodes with duplicate keys, an
288
+ # arbitrary one is deleted.
289
+ #
290
+ # Complexity: amortized O(log n)
291
+ #
292
+ # minheap = MinHeap.new([1, 2])
293
+ # minheap.delete(1) #=> 1
294
+ # minheap.size #=> 1
295
+ def delete(key)
296
+ pop if change_key(key, nil, true)
297
+ end
298
+
299
+ # Node class used internally
300
+ class Node # :nodoc:
301
+ attr_accessor :parent, :child, :left, :right, :key, :value, :degree, :marked
302
+
303
+ def initialize(key, value)
304
+ @key = key
305
+ @value = value
306
+ @degree = 0
307
+ @marked = false
308
+ @right = self
309
+ @left = self
310
+ end
311
+
312
+ def marked?
313
+ @marked == true
314
+ end
315
+
316
+ end
317
+
318
+ # make node a child of a parent node
319
+ def link_nodes(child, parent)
320
+ # link the child's siblings
321
+ child.left.right = child.right
322
+ child.right.left = child.left
323
+
324
+ child.parent = parent
325
+
326
+ # if parent doesn't have children, make new child its only child
327
+ if parent.child.nil?
328
+ parent.child = child.right = child.left = child
329
+ else # otherwise insert new child into parent's children list
330
+ current_child = parent.child
331
+ child.left = current_child
332
+ child.right = current_child.right
333
+ current_child.right.left = child
334
+ current_child.right = child
335
+ end
336
+ parent.degree += 1
337
+ child.marked = false
338
+ end
339
+ private :link_nodes
340
+
341
+ # Makes sure the structure does not contain nodes in the root list with
342
+ # equal degrees
343
+ def consolidate
344
+ roots = []
345
+ root = @next
346
+ min = root
347
+ # find the nodes in the list
348
+ loop do
349
+ roots << root
350
+ root = root.right
351
+ break if root == @next
352
+ end
353
+ degrees = []
354
+ roots.each do |root|
355
+ min = root if @compare_fn[root.key, min.key]
356
+ # check if we need to merge
357
+ if degrees[root.degree].nil? # no other node with the same degree
358
+ degrees[root.degree] = root
359
+ next
360
+ else # there is another node with the same degree, consolidate them
361
+ degree = root.degree
362
+ until degrees[degree].nil? do
363
+ other_root_with_degree = degrees[degree]
364
+ if @compare_fn[root.key, other_root_with_degree.key] # determine which node is the parent, which one is the child
365
+ smaller, larger = root, other_root_with_degree
366
+ else
367
+ smaller, larger = other_root_with_degree, root
368
+ end
369
+ link_nodes(larger, smaller)
370
+ degrees[degree] = nil
371
+ root = smaller
372
+ degree += 1
373
+ end
374
+ degrees[degree] = root
375
+ min = root if min.key == root.key # this fixes a bug with duplicate keys not being in the right order
376
+ end
377
+ end
378
+ @next = min
379
+ end
380
+ private :consolidate
381
+
382
+ def cascading_cut(node)
383
+ p = node.parent
384
+ if p
385
+ if node.marked?
386
+ cut(node, p)
387
+ cascading_cut(p)
388
+ else
389
+ node.marked = true
390
+ end
391
+ end
392
+ end
393
+ private :cascading_cut
394
+
395
+ # remove x from y's children and add x to the root list
396
+ def cut(x, y)
397
+ x.left.right = x.right
398
+ x.right.left = x.left
399
+ y.degree -= 1
400
+ if (y.degree == 0)
401
+ y.child = nil
402
+ elsif (y.child == x)
403
+ y.child = x.right
404
+ end
405
+ x.right = @next
406
+ x.left = @next.left
407
+ @next.left = x
408
+ x.left.right = x
409
+ x.parent = nil
410
+ x.marked = false
411
+ end
412
+ private :cut
413
+
414
+ end
415
+
416
+ # A MaxHeap is a heap where the items are returned in descending order of
417
+ # key value.
418
+ class MaxHeap < Heap
419
+
420
+ # call-seq:
421
+ # MaxHeap.new(ary) -> new_heap
422
+ #
423
+ # Creates a new MaxHeap with an optional array parameter of items to
424
+ # insert into the heap. A MaxHeap is created by calling
425
+ # Heap.new { |x, y| (x <=> y) == 1 }, so this is a convenience class.
426
+ #
427
+ # maxheap = MaxHeap.new([1, 2, 3, 4])
428
+ # maxheap.pop #=> 4
429
+ # maxheap.pop #=> 3
430
+ def initialize(ary=[])
431
+ super(ary) { |x, y| (x <=> y) == 1 }
432
+ end
433
+
434
+ # call-seq:
435
+ # max -> value
436
+ # max -> nil
437
+ #
438
+ # Returns the item with the largest key, but does not remove it from the
439
+ # heap.
440
+ #
441
+ # maxheap = MaxHeap.new([1, 2, 3, 4])
442
+ # maxheap.max #=> 4
443
+ def max
444
+ self.next
445
+ end
446
+
447
+ # call-seq:
448
+ # max! -> value
449
+ # max! -> nil
450
+ #
451
+ # Returns the item with the largest key and removes it from the heap.
452
+ #
453
+ # maxheap = MaxHeap.new([1, 2, 3, 4])
454
+ # maxheap.max! #=> 4
455
+ # maxheap.size #=> 3
456
+ def max!
457
+ self.pop
458
+ end
459
+ end
460
+
461
+ # A MinHeap is a heap where the items are returned in ascending order of
462
+ # key value.
463
+ class MinHeap < Heap
464
+
465
+ # call-seq:
466
+ # MinHeap.new(ary) -> new_heap
467
+ #
468
+ # Creates a new MinHeap with an optional array parameter of items to
469
+ # insert into the heap.
470
+ # A MinHeap is created by calling Heap.new { |x, y| (x <=> y) == -1 },
471
+ # so this is a convenience class.
472
+ #
473
+ # minheap = MinHeap.new([1, 2, 3, 4])
474
+ # minheap.pop #=> 1
475
+ # minheap.pop #=> 2
476
+ def initialize(ary=[])
477
+ super(ary) { |x, y| (x <=> y) == -1 }
478
+ end
479
+
480
+ # call-seq:
481
+ # min -> value
482
+ # min -> nil
483
+ #
484
+ # Returns the item with the smallest key, but does not remove it from
485
+ # the heap.
486
+ #
487
+ # minheap = MinHeap.new([1, 2, 3, 4])
488
+ # minheap.min #=> 1
489
+ def min
490
+ self.next
491
+ end
492
+
493
+ # call-seq:
494
+ # min! -> value
495
+ # min! -> nil
496
+ #
497
+ # Returns the item with the smallest key and removes it from the heap.
498
+ #
499
+ # minheap = MinHeap.new([1, 2, 3, 4])
500
+ # minheap.min! #=> 1
501
+ # minheap.size #=> 3
502
+ def min!
503
+ self.pop
504
+ end
505
+ end
506
+ end
507
+ end