algorithms 0.3.0-jruby

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