algorithms 0.0.1

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