algorithms 0.0.1

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.
@@ -0,0 +1,514 @@
1
+ # This is a fibonacci heap priority queue implementation.
2
+ # (c) 2005 Brian Amberg
3
+ # Please submit bugreports to mail@brian-amberg.de
4
+
5
+ # Modifications by Kanwei Li
6
+ module Containers
7
+ class RubyPriorityQueue
8
+ include Enumerable
9
+
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
413
+
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
505
+
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
513
+ end
514
+ end