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
@@ -0,0 +1,87 @@
1
+ =begin rdoc
2
+
3
+ A kd-tree allows searching of points in multi-dimensional space, increasing
4
+ efficiency for nearest-neighbor searching in particular.
5
+
6
+ =end
7
+
8
+ class Containers::KDTree
9
+ Node = Struct.new(:id, :coords, :left, :right)
10
+
11
+ def initialize(points)
12
+ @root = build_tree(points)
13
+ @nearest = []
14
+ end
15
+
16
+ # Build a kd-tree
17
+ def build_tree(points, depth=0)
18
+ return if points.empty?
19
+
20
+ axis = depth % 2
21
+
22
+ points.sort! { |a, b| a[1][axis] <=> b[1][axis] }
23
+ median = points.size / 2
24
+
25
+ node = Node.new(points[median][0], points[median][1], nil, nil)
26
+ node.left = build_tree(points[0...median], depth+1)
27
+ node.right = build_tree(points[median+1..-1], depth+1)
28
+ node
29
+ end
30
+ private :build_tree
31
+
32
+ # Euclidian distanced, squared, between a node and target coords
33
+ def distance2(node, target)
34
+ return nil if node.nil? or target.nil?
35
+ c = (node.coords[0] - target[0])
36
+ d = (node.coords[1] - target[1])
37
+ c * c + d * d
38
+ end
39
+ private :distance2
40
+
41
+ # Update array of nearest elements if necessary
42
+ def check_nearest(nearest, node, target, k_nearest)
43
+ d = distance2(node, target)
44
+ if nearest.size < k_nearest || d < nearest.last[0]
45
+ nearest.pop if nearest.size >= k_nearest
46
+ nearest << [d, node.id]
47
+ nearest.sort! { |a, b| a[0] <=> b[0] }
48
+ end
49
+ nearest
50
+ end
51
+
52
+ # Find k closest points to given coordinates
53
+ def find_nearest(target, k_nearest)
54
+ @nearest = []
55
+ nearest(@root, target, k_nearest, 0)
56
+ end
57
+
58
+ def nearest(node, target, k_nearest, depth)
59
+ axis = depth % 2
60
+
61
+ if node.left.nil? && node.right.nil? # Leaf node
62
+ @nearest = check_nearest(@nearest, node, target, k_nearest)
63
+ return
64
+ end
65
+
66
+ # Go down the nearest split
67
+ if node.right.nil? || (node.left && target[axis] <= node.coords[axis])
68
+ nearer = node.left
69
+ further = node.right
70
+ else
71
+ nearer = node.right
72
+ further = node.left
73
+ end
74
+ nearest(nearer, target, k_nearest, depth+1)
75
+
76
+ # See if we have to check other side
77
+ if further
78
+ if @nearest.size < k_nearest || (target[axis] - node.coords[axis])**2 < @nearest.last[0]
79
+ nearest(further, target, k_nearest, depth+1)
80
+ end
81
+ end
82
+
83
+ @nearest = check_nearest(@nearest, node, target, k_nearest)
84
+ end
85
+ private :nearest
86
+
87
+ end
@@ -1,514 +1,113 @@
1
- # This is a fibonacci heap priority queue implementation.
2
- # (c) 2005 Brian Amberg
3
- # Please submit bugreports to mail@brian-amberg.de
1
+ require 'containers/heap'
4
2
 
5
- # Modifications by Kanwei Li
6
- module Containers
7
- class RubyPriorityQueue
8
- include Enumerable
3
+ =begin rdoc
4
+ A Priority Queue is a data structure that behaves like a queue except that elements have an
5
+ associated priority. The #next and #pop methods return the item with the next highest priority.
9
6
 
10
- # Returns the number of elements of the queue.
11
- #
12
- # q = PriorityQueue.new
13
- # q.length #=> 0
14
- # q[0] = 1
15
- # q.length #=> 1
16
- attr_reader :length
17
-
18
- # Create a new, empty PriorityQueue
19
- def initialize
20
- @nodes = Hash.new
21
- @rootlist = nil
22
- @min = nil
23
- @length = 0
24
- end
25
-
26
- # Print a priority queue as a dot-graph. The output can be fed to dot from the
27
- # vizgraph suite to create a tree depicting the internal datastructure.
28
- def to_dot
29
- r = ["digraph fibheap {"]
30
- #r << @rootlist.to_dot.join("\n") if @rootlist
31
- r << "ROOT -> #{@rootlist.dot_id};" if @rootlist
32
- @nodes.to_a.sort.each do | (_, n) |
33
- r << " #{n.dot_id} [label=\"#{n.key}: #{n.priority}\"];"
34
- r << " #{n.dot_id} -> #{n.right.dot_id} [constraint=false];" if n.right# and n.dot_id < n.right.dot_id
35
- r << " #{n.dot_id} -> #{n.left.dot_id} [constraint=false];" if n.left #and n.dot_id < n.left.dot_id
36
- r << " #{n.dot_id} -> #{n.child.dot_id}" if n.child
37
- end
38
- r << "}"
39
- r.join("\n")
40
- r
41
- end
42
-
43
- # Call dot and gv displaying the datstructure
44
- def display_dot
45
- puts to_dot
46
- system "echo '#{to_dot}' | twopi -Tps -Groot=ROOT -Goverlap=false> /tmp/dotfile.ps; gv /tmp/dotfile.ps"
47
- end
48
-
49
- # call-seq:
50
- # [key] = priority
51
- # change_priority(key, priority)
52
- # push(key, priority)
53
- #
54
- # Set the priority of a key.
55
- #
56
- # q = PriorityQueue.new
57
- # q["car"] = 50
58
- # q["train"] = 50
59
- # q["bike"] = 10
60
- # q.min #=> ["bike", 10]
61
- # q["car"] = 0
62
- # q.min #=> ["car", 0]
63
- def change_priority(key, priority)
64
- return push(key, priority) unless @nodes[key]
65
-
66
- n = @nodes[key]
67
- if n.priority < priority # Priority was increased. Remove the node and reinsert.
68
- self.delete(key)
69
- self.push(key, priority);
70
- return self
71
- end
72
- n.priority = priority;
73
- @min = n if n.priority < @min.priority
74
-
75
- return self if !n.parent or n.parent.priority <= n.priority # Already in rootlist or bigger than parent
76
- begin # Cascading Cuts
77
- p = n.parent
78
- cut_node(n)
79
- n = p
80
- end while n.mark and n.parent
81
- n.mark = true if n.parent
82
-
83
- self
84
- end
85
-
86
- # Add an object to the queue.
87
- def push(key, priority)
88
- return change_priority(key, priority) if @nodes[key]
89
- @nodes[key] = node = Node.new(key, priority)
90
- @min = node if !@min or priority < @min.priority
91
- if not @rootlist
92
- @rootlist = node
93
- node.left = node.right = node
94
- else
95
- node.left = @rootlist.left
96
- node.right = @rootlist
97
- @rootlist.left.right = node
98
- @rootlist.left = node
99
- end
100
- @length += 1
101
- self
102
- end
103
-
104
- # Returns true if the array is empty, false otherwise.
105
- def empty?
106
- @rootlist.nil?
107
- end
108
-
109
- # call-seq:
110
- # [key] -> priority
111
- #
112
- # Return the priority of a key or nil if the key is not in the queue.
113
- #
114
- # q = PriorityQueue.new
115
- # (0..10).each do | i | q[i.to_s] = i end
116
- # q["5"] #=> 5
117
- # q[5] #=> nil
118
- def [](key)
119
- @nodes[key] and @nodes[key].priority
120
- end
121
-
122
- # call-seq:
123
- # has_key? key -> boolean
124
- #
125
- # Return false if the key is not in the queue, true otherwise.
126
- #
127
- # q = PriorityQueue.new
128
- # (0..10).each do | i | q[i.to_s] = i end
129
- # q.has_key("5") #=> true
130
- # q.has_key(5) #=> false
131
- def has_key?(key)
132
- @nodes.has_key?(key)
133
- end
134
-
135
- alias :[]= :push
136
-
137
- # Call the given block with each [key, priority] pair in the queue
138
- #
139
- # Beware: Changing the queue in the block may lead to unwanted behaviour and
140
- # even infinite loops.
141
- def each
142
- @nodes.each do | key, node |
143
- yield(key, node.priority)
144
- end
145
- end
146
-
147
- # call-seq:
148
- # min -> [object, priority]
149
- #
150
- # Return the pair [object, priority] with minimal priority or nil when the
151
- # queue is empty.
152
- #
153
- # q = PriorityQueue.new
154
- # q["a"] = 10
155
- # q["b"] = 20
156
- # q.min #=> ["a", 10]
157
- # q.delete_min #=> ["a", 10]
158
- # q.min #=> ["b", 20]
159
- # q.delete_min #=> ["b", 20]
160
- # q.min #=> nil
161
- def min
162
- [@min.key, @min.priority] rescue nil
163
- end
164
-
165
- # call-seq:
166
- # min_key -> object
167
- #
168
- # Return the key that has the minimal priority or nil when the queue is empty.
169
- #
170
- # q = PriorityQueue.new
171
- # q["a"] = 10
172
- # q["b"] = 20
173
- # q.min_key #=> "a"
174
- # q.delete_min #=> ["a", 10]
175
- # q.min_key #=> "b"
176
- # q.delete_min #=> ["b", 20]
177
- # q.min_key #=> nil
178
- def min_key
179
- @min.key rescue nil
180
- end
181
-
182
- # call-seq:
183
- # min_priority -> priority
184
- #
185
- # Return the minimal priority or nil when the queue is empty.
186
- #
187
- # q = PriorityQueue.new
188
- # q["a"] = 10
189
- # q["b"] = 20
190
- # q.min_priority #=> 10
191
- # q.delete_min #=> ["a", 10]
192
- # q.min_priority #=> 20
193
- # q.delete_min #=> ["b", 20]
194
- # q.min_priority #=> nil
195
- def min_priority
196
- @min.priority rescue nil
197
- end
198
-
199
- # call-seq:
200
- # delete(key) -> [key, priority]
201
- # delete(key) -> nil
202
- #
203
- # Delete a key from the priority queue. Returns nil when the key was not in
204
- # the queue and [key, priority] otherwise.
205
- #
206
- # q = PriorityQueue.new
207
- # (0..10).each do | i | q[i.to_s] = i end
208
- # q.delete(5) #=> ["5", 5]
209
- # q.delete(5) #=> nil
210
- def delete(key)
211
- return nil unless n = @nodes.delete(key)
212
-
213
- if n.child
214
- c = n.child
215
- e = n.child
216
- begin
217
- r = c.right
218
- cut_node(c)
219
- c = r
220
- end while c != e
221
- end
222
- cut_node(n) if n.parent
223
-
224
- if n == n.right
225
- @min = nil;
226
- @rootlist = nil;
227
- else
228
- @rootlist = n.right if @rootlist == n
229
- if @min == n
230
- n1 = n.right
231
- @min = n1
232
- begin
233
- @min = n1 if n1.priority < @min.priority
234
- n1 = n1.right
235
- end while(n1 != n);
236
- end
237
- n.right.left = n.left
238
- n.left.right = n.right
239
- n.left = n
240
- n.right = n
241
- end
242
- @length -= 1
243
- return [n.key, n.priority]
244
- end
245
-
246
- # call-seq:
247
- # delete_min_return_key -> key
248
- #
249
- # Delete key with minimal priority and return the key
250
- #
251
- # q = PriorityQueue.new
252
- # q["a"] = 1
253
- # q["b"] = 0
254
- # q.delete_min_return_key #=> "b"
255
- # q.delete_min_return_key #=> "a"
256
- # q.delete_min_return_key #=> nil
257
- def delete_min_return_key
258
- delete_min[0] rescue nil
259
- end
260
-
261
- # call-seq:
262
- # delete_min_return_priority -> priority
263
- #
264
- # Delete key with minimal priority and return the priority value
265
- #
266
- # q = PriorityQueue.new
267
- # q["a"] = 1
268
- # q["b"] = 0
269
- # q.delete_min_return_priority #=> 0
270
- # q.delete_min_return_priority #=> 1
271
- # q.delete_min_return_priority #=> nil
272
- def delete_min_return_priority
273
- delete_min[1] rescue nil
274
- end
275
-
276
- # call-seq:
277
- # delete_min -> [key, priority]
278
- #
279
- # Delete key with minimal priority and return [key, priority]
280
- #
281
- # q = PriorityQueue.new
282
- # q["a"] = 1
283
- # q["b"] = 0
284
- # q.delete_min #=> ["b", 0]
285
- # q.delete_min #=> ["a", 1]
286
- # q.delete_min #=> nil
287
- def delete_min
288
- return nil if self.empty?
289
- result = self.min
290
-
291
- @nodes.delete(@min.key)
292
-
293
- if @length == 1
294
- @rootlist = @min = nil
295
- @length = 0
296
- else
297
- min = @min
298
- if @min == @rootlist # If the rootlist is anchored at the minimum, shift to the right
299
- if @rootlist == @rootlist.right
300
- @rootlist = @min = nil
301
- else
302
- @rootlist = @min = @min.right
303
- end
304
- end
305
- min.left.right = min.right;
306
- min.right.left = min.left;
307
- min.left = min.right = min;
308
- if min.child
309
- # Kinder und Eltern trennen, Markierung aufheben
310
- n = min.child;
311
- begin
312
- n.parent = nil;
313
- n.mark = false;
314
- n = n.right;
315
- end while n != min.child
316
-
317
- # Kinder einf�gen
318
- if @rootlist
319
- l1 = @rootlist.left
320
- l2 = n.left
321
-
322
- l1.right = n
323
- n.left = l1
324
- l2.right = @rootlist
325
- @rootlist.left = l2
326
- else
327
- @rootlist = n
328
- end
329
- end
330
-
331
- # Gr��e anpassen
332
- @length -= 1
333
-
334
- # Wieder aufh�bschen
335
- consolidate
336
- end
337
-
338
- result
339
- end
340
-
341
- # Returns a string representation of the priority queue.
342
- def inspect
343
- "<PriorityQueue: #{@nodes.map{|(_, n)| [n.key, n.priority]}.sort_by{|(_,p)|p}.inspect}>"
344
- end
345
-
346
- def initialize_copy(copy)
347
- copy_nodes = @nodes
348
- @nodes = {}
349
-
350
- copy_nodes.each do | (_, cn) |
351
- n = @nodes[cn.key] = Node.new(cn.key, cn.priority)
352
- n.mark = cn.mark
353
- n.degree = cn.degree
354
- end
355
-
356
- copy_nodes.each do | (_, cn) |
357
- n = @nodes[cn.key]
358
- n.left = @nodes[cn.left.key] if cn.left
359
- n.right = @nodes[cn.right.key] if cn.right
360
- n.parent = @nodes[cn.parent.key] if cn.parent
361
- n.child = @nodes[cn.child.key] if cn.child
362
- end
363
- @rootlist = @nodes[@rootlist.key] if @rootlist
364
- @min = @nodes[@min.key] if @min
365
- self
366
- end
367
-
368
- # Node class used internally
369
- class Node # :nodoc:
370
- attr_accessor :parent, :child, :left, :right, :key, :priority, :degree, :mark
371
-
372
- def child=(c)
373
- raise "Circular Child" if c == self
374
- raise "Child is neighbour" if c == self.right
375
- raise "Child is neighbour" if c == self.left
376
- @child = c
377
- end
378
-
379
- def to_dot(only_down = false, known_nodes = [])
380
- p known_nodes.map { | n | n.dot_id }
381
- p self.dot_id
382
- result = []
383
- if only_down
384
- raise "Circular #{caller.inspect}" if known_nodes.include?(self)
385
- known_nodes << self
386
-
387
- result << "#{dot_id} [label=\"#{@key}: #{@priority}\"];"
388
- l = " "
389
- #l << "#{@left.dot_id} <- #{dot_id}; " if @left
390
- l << "#{dot_id} -> #{@left.dot_id} [constraint=false]; " if @left and @left.dot_id < self.dot_id
391
- l << "#{dot_id} -> #{@right.dot_id} [constraint=false];\t\t\t\t/*neighbours*/" if @right and @right.dot_id <= self.dot_id
392
- result << l
393
- result << " #{dot_id} -> #{@child.dot_id}; //child" if @child
394
- result << @child.to_dot(false, known_nodes) if @child
395
- else
396
- n = self
397
- begin
398
- result.concat(n.to_dot(true, known_nodes))
399
- n = n.right
400
- end while n != self
401
- end
402
- result.flatten.map{|r| " " << r}
403
- end
404
-
405
- def dot_id
406
- "N#{@key}"
407
- end
408
-
409
- def initialize(key, priority)
410
- @key = key; @priority = priority; @degree = 0
411
- end
412
- end
7
+ Priority Queues are often used in graph problems, such as Dijkstra's Algorithm for shortest
8
+ path, and the A* search algorithm for shortest path.
413
9
 
414
-
415
- private
416
-
417
- def link_nodes(b1, b2)
418
- return link_nodes(b2, b1) if b2.priority < b1.priority
419
-
420
- b2.parent = b1
421
- child = b1.child
422
- b1.child = b2
423
- if child
424
- b2.left = child.left
425
- b2.left.right = b2
426
- b2.right = child
427
- child.left = b2
428
- else
429
- b2.left = b2
430
- b2.right = b2
431
- end
432
- b1.degree += 1
433
- b2.mark = false # TODO: Check if this is correct, or if b1 should be marked as false
434
- return b1
435
- end
436
-
437
- # Does not change length
438
- def delete_first
439
- return nil unless @rootlist
440
-
441
- result = @rootlist
442
- if result == result.right
443
- @min = @rootlist = nil
444
- else
445
- @rootlist = result.right
446
- @rootlist.left = result.left
447
- @rootlist.left.right = @rootlist
448
-
449
- result.right = result.left = result
450
- end
451
- return result;
452
- end
453
-
454
- def cut_node(n)
455
- return self unless n.parent
456
- n.parent.degree -= 1
457
- if n.parent.child == n
458
- if n.right == n
459
- n.parent.child = nil
460
- else
461
- n.parent.child = n.right;
462
- end
463
- end
464
- n.parent = nil
465
- n.right.left = n.left
466
- n.left.right = n.right
467
-
468
- n.right = @rootlist
469
- n.left = @rootlist.left
470
- @rootlist.left.right = n
471
- @rootlist.left = n
472
-
473
- n.mark = false
474
-
475
- return self
476
- end
477
-
478
- # Does not change length
479
- def insert_tree(tree)
480
- if @rootlist == nil
481
- @rootlist = @min = tree
482
- else
483
- l = @rootlist.left
484
- l.right = tree
485
- @rootlist.left = tree
486
- tree.left = l
487
- tree.right = @rootlist
488
- @min = tree if tree.priority < @min.priority
489
- end
490
- self
491
- end
492
-
493
- def consolidate
494
- return self if self.empty?
495
- array_size = (2.0 * Math.log(self.length) / Math.log(2) + 1.0).ceil
496
- tree_by_degree = Array.new(array_size)
497
-
498
- while n = delete_first
499
- while n1 = tree_by_degree[n.degree]
500
- tree_by_degree[n.degree] = nil;
501
- n = link_nodes(n, n1);
502
- end
503
- tree_by_degree[n.degree] = n;
504
- end
10
+ This container is implemented using the Fibonacci heap included in the Collections library.
11
+ =end
12
+ class Containers::PriorityQueue
13
+ include Enumerable
14
+
15
+ # Create a new, empty PriorityQueue
16
+ def initialize(&block)
17
+ # We default to a priority queue that returns the largest value
18
+ block ||= lambda { |x, y| (x <=> y) == 1 }
19
+ @heap = Containers::Heap.new(&block)
20
+ end
21
+
22
+ # Returns the number of elements in the queue.
23
+ #
24
+ # q = Containers::PriorityQueue.new
25
+ # q.size #=> 0
26
+ # q.push("Alaska", 1)
27
+ # q.size #=> 1
28
+ def size
29
+ @heap.size
30
+ end
31
+ alias_method :length, :size
32
+
33
+ # Add an object to the queue with associated priority.
34
+ #
35
+ # q = Containers::PriorityQueue.new
36
+ # q.push("Alaska", 1)
37
+ # q.pop #=> "Alaska"
38
+ def push(object, priority)
39
+ @heap.push(priority, object)
40
+ end
41
+
42
+ # Clears all the items in the queue.
43
+ def clear
44
+ @heap.clear
45
+ end
46
+
47
+ # Returns true if the queue is empty, false otherwise.
48
+ def empty?
49
+ @heap.empty?
50
+ end
505
51
 
506
- @rootlist = @min = nil;
507
- tree_by_degree.each do | tree |
508
- next unless tree
509
- insert_tree(tree)
510
- end
511
- self
512
- end
52
+ # call-seq:
53
+ # has_priority? priority -> boolean
54
+ #
55
+ # Return true if the priority is in the queue, false otherwise.
56
+ #
57
+ # q = PriorityQueue.new
58
+ # q.push("Alaska", 1)
59
+ #
60
+ # q.has_priority?(1) #=> true
61
+ # q.has_priority?(2) #=> false
62
+ def has_priority?(priority)
63
+ @heap.has_key?(priority)
64
+ end
65
+
66
+ # call-seq:
67
+ # next -> object
68
+ #
69
+ # Return the object with the next highest priority, but does not remove it
70
+ #
71
+ # q = Containers::PriorityQueue.new
72
+ # q.push("Alaska", 50)
73
+ # q.push("Delaware", 30)
74
+ # q.push("Georgia", 35)
75
+ # q.next #=> "Alaska"
76
+ def next
77
+ @heap.next
513
78
  end
79
+
80
+ # call-seq:
81
+ # pop -> object
82
+ #
83
+ # Return the object with the next highest priority and removes it from the queue
84
+ #
85
+ # q = Containers::PriorityQueue.new
86
+ # q.push("Alaska", 50)
87
+ # q.push("Delaware", 30)
88
+ # q.push("Georgia", 35)
89
+ # q.pop #=> "Alaska"
90
+ # q.size #=> 2
91
+ def pop
92
+ @heap.pop
93
+ end
94
+ alias_method :next!, :pop
95
+
96
+ # call-seq:
97
+ # delete(priority) -> object
98
+ # delete(priority) -> nil
99
+ #
100
+ # Delete an object with specified priority from the queue. If there are duplicates, an
101
+ # arbitrary object with that priority is deleted and returned. Returns nil if there are
102
+ # no objects with the priority.
103
+ #
104
+ # q = PriorityQueue.new
105
+ # q.push("Alaska", 50)
106
+ # q.push("Delaware", 30)
107
+ # q.delete(50) #=> "Alaska"
108
+ # q.delete(10) #=> nil
109
+ def delete(priority)
110
+ @heap.delete(priority)
111
+ end
112
+
514
113
  end