PriorityQueue 0.1.0

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,14 @@
1
+ # A priority queue implementation.
2
+ # This extension contains two implementations, a c extension and a pure ruby
3
+ # implementation. When the compiled extension can not be found, it falls back
4
+ # to the pure ruby extension.
5
+ #
6
+ # See CPriorityQueue and RubyPriorityQueue for more information.
7
+
8
+ begin
9
+ require 'priority_queue/CPriorityQueue'
10
+ PriorityQueue = CPriorityQueue
11
+ rescue LoadError # C Version could not be found, try ruby version
12
+ require 'priority_queue/ruby_priority_queue'
13
+ PriorityQueue = RubyPriorityQueue
14
+ end
@@ -0,0 +1,46 @@
1
+ # A Poor mans Priority Queue. (Very inefficent but minimal implemention).
2
+ class PoorPriorityQueue < Hash
3
+ def push(object, priority)
4
+ self[object] = priority
5
+ end
6
+
7
+ def min
8
+ return nil if self.empty?
9
+ min_k = self.keys.first
10
+ min_p = self[min_k]
11
+ self.each do | k, p |
12
+ min_k, min_p = k, p if p < min_p
13
+ end
14
+ [min_k, min_p]
15
+ end
16
+
17
+ def min_key
18
+ min[0] rescue nil
19
+ end
20
+
21
+ def min_priority
22
+ min[1] rescue nil
23
+ end
24
+
25
+ def delete_min
26
+ return nil if self.empty?
27
+ min_k, min_p = *min
28
+ self.delete(min_k)
29
+ [min_k, min_p]
30
+ end
31
+
32
+ def delete_min_return_key
33
+ delete_min[0] rescue nil
34
+ end
35
+
36
+ def delete_min_return_priority
37
+ delete_min[1] rescue nil
38
+ end
39
+
40
+ def delete(object)
41
+ return nil unless self.has_key?(object)
42
+ result = [object, self[object]]
43
+ super
44
+ result
45
+ end
46
+ end
@@ -0,0 +1,394 @@
1
+ # Pure ruby Priority Queue
2
+ $stdout.sync = true
3
+ $stderr.sync = true
4
+
5
+ class RubyPriorityQueue
6
+
7
+ private
8
+
9
+ def link_nodes(b1, b2)
10
+ return link_nodes(b2, b1) if b2.priority < b1.priority
11
+
12
+ b2.parent = b1
13
+ child = b1.child
14
+ b1.child = b2
15
+ if child
16
+ b2.left = child.left
17
+ b2.left.right = b2
18
+ b2.right = child
19
+ child.left = b2
20
+ else
21
+ b2.left = b2
22
+ b2.right = b2
23
+ end
24
+ b1.degree += 1
25
+ b2.mark = false # TODO: Check if this is correct, or if b1 should be marked as false
26
+ return b1
27
+ end
28
+
29
+ # Does not change length
30
+ def delete_first
31
+ return nil unless @rootlist
32
+
33
+ result = @rootlist
34
+ if result == result.right
35
+ @min = @rootlist = nil
36
+ else
37
+ @rootlist = result.right
38
+ @rootlist.left = result.left
39
+ @rootlist.left.right = @rootlist
40
+
41
+ result.right = result.left = result
42
+ end
43
+ return result;
44
+ end
45
+
46
+ def cut_node(n)
47
+ return self unless n.parent
48
+ n.parent.degree -= 1
49
+ if n.parent.child == n
50
+ if n.right == n
51
+ n.parent.child = nil
52
+ else
53
+ n.parent.child = n.right;
54
+ end
55
+ end
56
+ n.parent = nil
57
+ n.right.left = n.left
58
+ n.left.right = n.right
59
+
60
+ n.right = @rootlist
61
+ n.left = @rootlist.left
62
+ @rootlist.left.right = n
63
+ @rootlist.left = n
64
+
65
+ n.mark = false
66
+
67
+ return self
68
+ end
69
+
70
+ # Does not change length priority
71
+ def insert_tree(tree)
72
+ if @rootlist == nil
73
+ @rootlist = @min = tree
74
+ else
75
+ l = @rootlist.left
76
+ l.right = tree
77
+ @rootlist.left = tree
78
+ tree.left = l
79
+ tree.right = @rootlist
80
+ @min = tree if tree.priority < @min.priority
81
+ end
82
+ self
83
+ end
84
+
85
+ def consolidate
86
+ return self if self.empty?
87
+ array_size = (2.0 * Math.log(self.length) / Math.log(2) + 1.0).ceil
88
+ tree_by_degree = Array.new(array_size)
89
+
90
+ while n = delete_first
91
+ while n1 = tree_by_degree[n.degree]
92
+ tree_by_degree[n.degree] = nil;
93
+ n = link_nodes(n, n1);
94
+ end
95
+ tree_by_degree[n.degree] = n;
96
+ end
97
+
98
+ @rootlist = @min = nil;
99
+ tree_by_degree.each do | tree |
100
+ next unless tree
101
+ insert_tree(tree)
102
+ end
103
+ self
104
+ end
105
+
106
+ # Node class used internally
107
+ class Node # :nodoc:
108
+ attr_accessor :parent, :child, :left, :right, :key, :priority, :degree, :mark
109
+
110
+ def child=(c)
111
+ raise "Circular Child" if c == self
112
+ raise "Child is neighbour" if c == self.right
113
+ raise "Child is neighbour" if c == self.left
114
+ @child = c
115
+ end
116
+
117
+ def to_dot(only_down = false, known_nodes = [])
118
+ p known_nodes.map { | n | n.dot_id }
119
+ p self.dot_id
120
+ result = []
121
+ if only_down
122
+ raise "Circular #{caller.inspect}" if known_nodes.include?(self)
123
+ known_nodes << self
124
+
125
+ result << "#{dot_id} [label=\"#{@key}: #{@priority}\"];"
126
+ l = " "
127
+ #l << "#{@left.dot_id} <- #{dot_id}; " if @left
128
+ l << "#{dot_id} -> #{@left.dot_id} [constraint=false]; " if @left and @left.dot_id < self.dot_id
129
+ l << "#{dot_id} -> #{@right.dot_id} [constraint=false];\t\t\t\t/*neighbours*/" if @right and @right.dot_id <= self.dot_id
130
+ result << l
131
+ result << " #{dot_id} -> #{@child.dot_id}; //child" if @child
132
+ result << @child.to_dot(false, known_nodes) if @child
133
+ else
134
+ n = self
135
+ begin
136
+ result.concat(n.to_dot(true, known_nodes))
137
+ n = n.right
138
+ end while n != self
139
+ end
140
+ result.flatten.map{|r| " " << r}
141
+ end
142
+
143
+ def dot_id
144
+ "N#{@key}"
145
+ end
146
+
147
+ def initialize(key, priority)
148
+ @key = key; @priority = priority; @degree = 0
149
+ end
150
+ end
151
+
152
+ public
153
+
154
+ attr_reader :length
155
+
156
+ def initialize
157
+ @nodes = Hash.new
158
+ @rootlist = nil
159
+ @min = nil
160
+ @length = 0
161
+ end
162
+
163
+ def to_dot
164
+ r = ["digraph fibheap {"]
165
+ #r << @rootlist.to_dot.join("\n") if @rootlist
166
+ r << "ROOT -> #{@rootlist.dot_id};" if @rootlist
167
+ @nodes.to_a.sort.each do | (_, n) |
168
+ r << " #{n.dot_id} [label=\"#{n.key}: #{n.priority}\"];"
169
+ r << " #{n.dot_id} -> #{n.right.dot_id} [constraint=false];" if n.right# and n.dot_id < n.right.dot_id
170
+ r << " #{n.dot_id} -> #{n.left.dot_id} [constraint=false];" if n.left #and n.dot_id < n.left.dot_id
171
+ r << " #{n.dot_id} -> #{n.child.dot_id}" if n.child
172
+ end
173
+ r << "}"
174
+ r.join("\n")
175
+ r
176
+ end
177
+
178
+ def display_dot
179
+ puts to_dot
180
+ system "echo '#{to_dot}' | twopi -Tps -Groot=ROOT -Goverlap=false> /tmp/dotfile.ps; gv /tmp/dotfile.ps"
181
+ end
182
+
183
+ def change_priority(key, priority)
184
+ return push(key, priority) unless @nodes[key]
185
+
186
+ n = @nodes[key]
187
+ if n.priority < priority # Priority was increased. Remove the node and reinsert.
188
+ self.delete(key)
189
+ self.push(key, priority);
190
+ return self
191
+ end
192
+ n.priority = priority;
193
+ @min = n if n.priority < @min.priority
194
+
195
+ return self if !n.parent or n.parent.priority <= n.priority # Already in rootlist or bigger than parent
196
+ begin # Cascading Cuts
197
+ p = n.parent
198
+ cut_node(n)
199
+ n = p
200
+ end while n.mark and n.parent
201
+ n.mark = true if n.parent
202
+
203
+ self
204
+ end
205
+
206
+ def push(key, priority)
207
+ return change_priority(key, priority) if @nodes[key]
208
+ @nodes[key] = node = Node.new(key, priority)
209
+ @min = node if !@min or priority < @min.priority
210
+ if not @rootlist
211
+ @rootlist = node
212
+ node.left = node.right = node
213
+ else
214
+ node.left = @rootlist.left
215
+ node.right = @rootlist
216
+ @rootlist.left.right = node
217
+ @rootlist.left = node
218
+ end
219
+ @length += 1
220
+ self
221
+ end
222
+
223
+ def empty?
224
+ @rootlist.nil?
225
+ end
226
+
227
+ def [](key)
228
+ @nodes[key] and @nodes[key].priority
229
+ end
230
+
231
+ def has_key?(key)
232
+ @nodes.has_key?(key)
233
+ end
234
+
235
+ alias :[]= :push
236
+
237
+ def each
238
+ @nodes.each do | key, node |
239
+ yield(key, node.priority)
240
+ end
241
+ end
242
+
243
+ include Enumerable
244
+
245
+ def min
246
+ [@min.key, @min.priority] rescue nil
247
+ end
248
+
249
+ def min_key
250
+ @min.key rescue nil
251
+ end
252
+
253
+ def min_priority
254
+ @min.priority rescue nil
255
+ end
256
+
257
+ def delete_min_return_key
258
+ delete_min[0] rescue nil
259
+ end
260
+
261
+ def delete_min_return_priority
262
+ delete_min[1] rescue nil
263
+ end
264
+
265
+ def delete(key)
266
+ return nil unless n = @nodes.delete(key)
267
+
268
+ if n.child
269
+ c = n.child
270
+ e = n.child
271
+ begin
272
+ r = c.right
273
+ cut_node(c)
274
+ c = r
275
+ end while c != e
276
+ end
277
+ cut_node(n) if n.parent
278
+
279
+ if n == n.right
280
+ @min = nil;
281
+ @rootlist = nil;
282
+ else
283
+ @rootlist = n.right if @rootlist == n
284
+ if @min == n
285
+ n1 = n.right
286
+ @min = n1
287
+ begin
288
+ @min = n1 if n1.priority < @min.priority
289
+ n1 = n1.right
290
+ end while(n1 != n);
291
+ end
292
+ n.right.left = n.left
293
+ n.left.right = n.right
294
+ n.left = n
295
+ n.right = n
296
+ end
297
+ @length -= 1
298
+ return [n.key, n.priority]
299
+ end
300
+
301
+ def delete_min
302
+ return nil if self.empty?
303
+ result = self.min
304
+
305
+ @nodes.delete(@min.key)
306
+
307
+ if @length == 1
308
+ @rootlist = @min = nil
309
+ @length = 0
310
+ else
311
+ min = @min
312
+ if @min == @rootlist # If the rootlist is anchored at the minimum, shift to the right
313
+ if @rootlist == @rootlist.right
314
+ @rootlist = @min = nil
315
+ else
316
+ @rootlist = @min = @min.right
317
+ end
318
+ end
319
+ min.left.right = min.right;
320
+ min.right.left = min.left;
321
+ min.left = min.right = min;
322
+ if min.child
323
+ # Kinder und Eltern trennen, Markierung aufheben
324
+ n = min.child;
325
+ begin
326
+ n.parent = nil;
327
+ n.mark = false;
328
+ n = n.right;
329
+ end while n != min.child
330
+
331
+ # Kinder einf�gen
332
+ if @rootlist
333
+ l1 = @rootlist.left
334
+ l2 = n.left
335
+
336
+ l1.right = n
337
+ n.left = l1
338
+ l2.right = @rootlist
339
+ @rootlist.left = l2
340
+ else
341
+ @rootlist = n
342
+ end
343
+ end
344
+
345
+ # Gr��e anpassen
346
+ @length -= 1
347
+
348
+ # Wieder aufh�bschen
349
+ consolidate
350
+ end
351
+
352
+ result
353
+ end
354
+
355
+ def inspect
356
+ "<PriorityQueue: #{@nodes.map{|(_, n)| [n.key, n.priority]}.sort_by{|(_,p)|p}.inspect}>"
357
+ end
358
+
359
+ def initialize_copy(copy)
360
+ copy_nodes = @nodes
361
+ @nodes = {}
362
+
363
+ copy_nodes.each do | (_, cn) |
364
+ n = @nodes[cn.key] = Node.new(cn.key, cn.priority)
365
+ n.mark = cn.mark
366
+ n.degree = cn.degree
367
+ end
368
+
369
+ copy_nodes.each do | (_, cn) |
370
+ n = @nodes[cn.key]
371
+ n.left = @nodes[cn.left.key] if cn.left
372
+ n.right = @nodes[cn.right.key] if cn.right
373
+ n.parent = @nodes[cn.parent.key] if cn.parent
374
+ n.child = @nodes[cn.child.key] if cn.child
375
+ end
376
+ @rootlist = @nodes[@rootlist.key] if @rootlist
377
+ @min = @nodes[@min.key] if @min
378
+ self
379
+ end
380
+ end
381
+
382
+ if __FILE__ == $0
383
+ q = RubyPriorityQueue.new
384
+
385
+ ('a'..'z').each do | n |
386
+ q[n] = n[0]
387
+ end
388
+ q.delete_min
389
+ q.delete_min
390
+ q.delete_min
391
+ q.delete_min
392
+ q.display_dot
393
+ q.delete_min
394
+ end