algorithms 0.3.0-jruby

Sign up to get free protection for your applications and to get access to all the features.
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