pqueue 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.ruby ADDED
@@ -0,0 +1,58 @@
1
+ ---
2
+ source:
3
+ - meta
4
+ authors:
5
+ - name: K. Kodama
6
+ - name: Ronald Butler
7
+ - name: Olivier Renaud
8
+ - name: Rick Bradley
9
+ - name: Thomas Sawyer
10
+ email: transfire@gmail.com
11
+ copyrights:
12
+ - holder: K. Kodama
13
+ year: '2001'
14
+ replacements: []
15
+ alternatives: []
16
+ requirements:
17
+ - name: detroit
18
+ groups:
19
+ - build
20
+ development: true
21
+ - name: microtest
22
+ groups:
23
+ - test
24
+ development: true
25
+ - name: ae
26
+ groups:
27
+ - test
28
+ development: true
29
+ dependencies: []
30
+ conflicts: []
31
+ repositories:
32
+ - uri: git://github.com/rubyworks/pqueue.git
33
+ scm: git
34
+ name: upstream
35
+ resources:
36
+ home: http://rubyworks.github.com/pqueue
37
+ code: http://github.com/rubyworks/pqueue
38
+ mail: http://groups.google.com/group/rubyworks-mailinglist
39
+ bugs: http://github.com/rubyworks/pqueue/issues
40
+ extra: {}
41
+ load_path:
42
+ - lib
43
+ revision: 0
44
+ created: '2001-03-10'
45
+ summary: Queue of Prioritized Elements
46
+ title: PQueue
47
+ version: 2.0.0
48
+ name: pqueue
49
+ description: ! 'A priority queue is like a standard queue, except that each inserted
50
+ elements
51
+
52
+ is given a certain priority, based on the result of the comparison block given
53
+
54
+ at instantiation time. Retrieving an element from the queue will always return
55
+
56
+ the one with the highest priority.'
57
+ organization: rubyworks
58
+ date: '2011-10-29'
@@ -0,0 +1,31 @@
1
+ = COPYRIGHT NOTICES
2
+
3
+ == PQueue
4
+
5
+ Copyright:: (c) 2011 Rubyworks
6
+ License:: BSD-2-Clause
7
+ Website:: http://rubyworks.github.com/pqueue
8
+
9
+ Copyright 2011 Rubyworks. All rights reserved.
10
+
11
+ Redistribution and use in source and binary forms, with or without
12
+ modification, are permitted provided that the following conditions are met:
13
+
14
+ 1. Redistributions of source code must retain the above copyright notice,
15
+ this list of conditions and the following disclaimer.
16
+
17
+ 2. Redistributions in binary form must reproduce the above copyright
18
+ notice, this list of conditions and the following disclaimer in the
19
+ documentation and/or other materials provided with the distribution.
20
+
21
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
22
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
23
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24
+ COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
28
+ OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
+
@@ -0,0 +1,28 @@
1
+ = CHANGE HISTORY
2
+
3
+ == 2.0.0 / 2011-10-29
4
+
5
+ This is a complete rewrite to simplify the design and use more
6
+ of Ruby's internal methods. Overall performance should be markedly
7
+ improved. A few method names have changed to be more consistent with
8
+ Ruby's other data structure. Note that the internal heap is now in reverse
9
+ order from the previous version. If using #to_a be aware that the priority
10
+ order will be reversed. This release also switches the library to
11
+ distribution under the BSD-2-Clause license.
12
+
13
+ Changes:
14
+
15
+ * Rewrite library.
16
+ * Modernize build configuration.
17
+ * Switch to BSD-2-Clause license.
18
+
19
+
20
+ == 1.0.0 / 2009-07-05
21
+
22
+ This is the initial standalone release of PQueue, spun-off from the
23
+ Ruby Facets and originally written by K. Komada.
24
+
25
+ Changes:
26
+
27
+ * Happy New Birthday!
28
+
@@ -0,0 +1,57 @@
1
+ = PQueue
2
+
3
+ {Home}[http://rubyworks.github.com/pqueue] |
4
+ {Code}[http://github.com/rubyworks/pqueue] |
5
+ {Docs}[http://rubydoc.info/gems/pqueue/frames] |
6
+ {Mail}[http://groups.google.com/group/rubyworks] | #rubyworks
7
+
8
+ {<img src="http://travis-ci.org/rubyworks/pqueue.png" />}[http://travis-ci.org/rubyworks/pqueue]
9
+
10
+ == DESCRIPTION
11
+
12
+ Priority queue with array based heap.
13
+
14
+ A priority queue is like a standard queue, except that each inserted
15
+ elements is given a certain priority, based on the result of the
16
+ comparison block given at instantiation time. Also, retrieving an element
17
+ from the queue will always return the one with the highest priority
18
+ (see #pop and #top).
19
+
20
+ The default is to compare the elements in respect to their #<=> method.
21
+ For example, Numeric elements with higher values will have higher
22
+ priorities.
23
+
24
+ This library is a rewrite of the original PQueue.rb by K. Kodama and
25
+ Heap.rb by Ronald Butler. The two libraries were later merged
26
+ and generally improved by Olivier Renaud. Then the whole library
27
+ rewritten by Trans using the original as a functional reference.
28
+
29
+
30
+ == SYNOPSIS
31
+
32
+ require 'pqueue'
33
+
34
+ pq = PQueue.new([2,3,1]){ |a,b| a > b }
35
+
36
+ pq.pop #=> 3
37
+
38
+
39
+ == ACKNOWLEDGMENTS
40
+
41
+ Although the library has been completely rewritten since, we still would
42
+ like to acknowledge the efforts of the original PQueue authors and
43
+ contributors.
44
+
45
+ * Olivier Renaud (2007)
46
+ * Rick Bradley (2003)
47
+ * Ronald Butler (2002)
48
+ * K Kodama (2001, original library)
49
+
50
+
51
+ == COPYRIGHTS
52
+
53
+ Copyright (c) 2011 Rubyworks
54
+
55
+ PQueue is distributable in accordance with the *FreeBSD* license.
56
+
57
+ See the COPYING.rdoc file for details.
@@ -6,147 +6,128 @@
6
6
  # from the queue will always return the one with the highest priority
7
7
  # (see #pop and #top).
8
8
  #
9
- # The default is to compare the elements in repect to their #> method.
9
+ # The default is to compare the elements in repect to their #<=> method.
10
10
  # For example, Numeric elements with higher values will have higher
11
11
  # priorities.
12
12
  #
13
+ # Note that as of version 2.0 the internal queue is kept in the reverse order
14
+ # from how it was kept in previous version. If you had used #to_a in the
15
+ # past then be sure to adjust for the priorities to be ordered back-to-front
16
+ # instead of the oterh way around.
17
+ #
13
18
  class PQueue
14
19
 
15
- # number of elements
16
- attr_reader :size
17
- # compare Proc
18
- attr_reader :gt
19
- attr_reader :qarray #:nodoc:
20
- protected :qarray
20
+ #
21
+ VERSION = "2.0.0" #:erb: VERSION = "<%= version %>"
21
22
 
23
+ #
22
24
  # Returns a new priority queue.
23
25
  #
24
26
  # If elements are given, build the priority queue with these initial
25
27
  # values. The elements object must respond to #to_a.
26
28
  #
27
29
  # If a block is given, it will be used to determine the priority between
28
- # the elements.
30
+ # the elements. The block must must take two arguments and return `1`, `0`,
31
+ # or `-1` or `true`, `nil` or `false. It should return `0` or `nil` if the
32
+ # two arguments are considered equal, return `1` or `true` if the first
33
+ # argument is considered greater than the later, and `-1` or `false` if
34
+ # the later is considred to be greater than the first.
29
35
  #
30
36
  # By default, the priority queue retrieves maximum elements first
31
- # (using the #> method).
37
+ # using the #<=> method.
38
+ #
32
39
  def initialize(elements=nil, &block) # :yields: a, b
33
- @qarray = [nil]
34
- @size = 0
35
- @gt = block || lambda {|a,b| a > b}
40
+ @que = []
41
+ @cmp = block || lambda{ |a,b| a <=> b }
36
42
  replace(elements) if elements
37
43
  end
38
44
 
39
- private
45
+ protected
40
46
 
41
- # Assumes that the tree is a heap, for nodes < k.
42
47
  #
43
- # The element at index k will go up until it finds its place.
44
- def upheap(k)
45
- k2 = k.div(2)
46
- v = @qarray[k]
47
- while k2 > 0 && @gt[v, @qarray[k2]]
48
- @qarray[k] = @qarray[k2]
49
- k = k2
50
- k2 = k2.div(2)
51
- end
52
- @qarray[k] = v
53
- end
48
+ # The underlying heap.
49
+ #
50
+ attr_reader :que #:nodoc:
54
51
 
55
- # Assumes the entire tree is a heap.
56
- #
57
- # The element at index k will go down until it finds its place.
58
- def downheap(k)
59
- v = @qarray[k]
60
- q2 = @size.div(2)
61
- loop {
62
- break if k > q2
63
- j = 2 * k
64
- if j < @size && @gt[@qarray[j+1], @qarray[j]]
65
- j += 1
66
- end
67
- break if @gt[v, @qarray[j]]
68
- @qarray[k] = @qarray[j]
69
- k = j
70
- }
71
- @qarray[k] = v;
72
- end
52
+ public
73
53
 
54
+ #
55
+ # Priority comparison procedure.
56
+ #
57
+ attr_reader :cmp
74
58
 
75
- # Recursive version of heapify. I kept the code, since it may be
76
- # easier to understand than the non-recursive one.
77
- # def heapify
78
- # @size.div(2).downto(1) {|i| h(i)}
79
- # end
80
- # def h(t)
81
- # l = 2 * t
82
- # r = l + 1
83
- # hi = if r > @size || @gt[@qarray[l],@qarray[r]] then l else r end
84
- # if @gt[@qarray[hi],@qarray[t]]
85
- # @qarray[hi], @qarray[t] = @qarray[t], @qarray[hi]
86
- # h(hi) if hi <= @size.div(2)
87
- # end
88
- # end
89
-
90
- # Make a heap out of an unordered array.
91
- def heapify
92
- @size.div(2).downto(1) do |t|
93
- begin
94
- l = 2 * t
95
- r = l + 1
96
- hi = if r > @size || @gt[@qarray[l],@qarray[r]] then l else r end
97
- if @gt[@qarray[hi],@qarray[t]]
98
- @qarray[hi], @qarray[t] = @qarray[t], @qarray[hi]
99
- if hi <= @size.div(2)
100
- t = hi
101
- redo
102
- end # if
103
- end #if
104
- end #begin
105
- end # downto
59
+ #
60
+ # Returns the size of the queue.
61
+ #
62
+ def size
63
+ @que.size
106
64
  end
107
65
 
108
- public
66
+ #
67
+ # Alias of size.
68
+ #
69
+ alias length size
109
70
 
71
+ #
110
72
  # Add an element in the priority queue.
111
73
  #
112
- # The insertion time is O(log n), with n the size of the queue.
113
74
  def push(v)
114
- @size += 1
115
- @qarray[@size] = v
116
- upheap(@size)
117
- return self
75
+ @que << v
76
+ reheap(@que.size-1)
77
+ self
118
78
  end
119
79
 
80
+ #
81
+ # Alias of #push.
82
+ #
120
83
  alias :<< :push
121
84
 
85
+ #
86
+ # Alias of #push.
87
+ #
88
+ alias enq push
89
+
90
+ #
122
91
  # Return the element with the highest priority and remove it from
123
92
  # the queue.
124
93
  #
125
- # The highest priority is determined by the block given at instanciation
94
+ # The highest priority is determined by the block given at instantiation
126
95
  # time.
127
96
  #
128
- # The deletion time is O(log n), with n the size of the queue.
97
+ # The deletion time is O(log n), with n is the size of the queue.
129
98
  #
130
99
  # Return nil if the queue is empty.
100
+ #
131
101
  def pop
132
102
  return nil if empty?
133
- res = @qarray[1]
134
- @qarray[1] = @qarray[@size]
135
- @size -= 1
136
- downheap(1)
137
- return res
103
+ @que.pop
138
104
  end
139
105
 
140
- # Return the element with the highest priority.
106
+ #
107
+ # Alias of #push.
108
+ #
109
+ alias shift push
110
+
111
+ #
112
+ # Alias of #pop.
113
+ #
114
+ alias deq push
115
+
116
+ #
117
+ # Returns the element with the highest priority, but
118
+ # does not remove it from the queue.
119
+ #
141
120
  def top
142
121
  return nil if empty?
143
- return @qarray[1]
122
+ return @que.last
144
123
  end
145
124
 
125
+ #
146
126
  # Add more than one element at the same time. See #push.
147
127
  #
148
- # The elements object must respond to #to_a, or to be a PQueue itself.
149
- def push_all(elements)
128
+ # The elements object must respond to #to_a, or be a PQueue itself.
129
+ #
130
+ def concat(elements)
150
131
  if empty?
151
132
  if elements.kind_of?(PQueue)
152
133
  initialize_copy(elements)
@@ -155,115 +136,182 @@ class PQueue
155
136
  end
156
137
  else
157
138
  if elements.kind_of?(PQueue)
158
- @qarray[@size + 1, elements.size] = elements.qarray[1..-1]
159
- elements.size.times{ @size += 1; upheap(@size)}
139
+ @que.concat(elements.que)
140
+ sort!
160
141
  else
161
- ary = elements.to_a
162
- @qarray[@size + 1, ary.size] = ary
163
- ary.size.times{ @size += 1; upheap(@size)}
142
+ @que.concat(elements.to_a)
143
+ sort!
164
144
  end
165
145
  end
166
146
  return self
167
147
  end
168
148
 
169
- alias :merge :push_all
170
-
149
+ #
150
+ # Alias for #concat.
151
+ #
152
+ alias :merge! :concat
171
153
 
154
+ #
172
155
  # Return top n-element as a sorted array.
173
- def pop_array(n=@size)
174
- ary = []
175
- n.times{ary.push(pop)}
176
- return ary
156
+ #
157
+ def take(n=@size)
158
+ a = []
159
+ n.times{a.push(pop)}
160
+ a
177
161
  end
178
162
 
179
-
180
- # True if there is no more elements left in the priority queue.
163
+ #
164
+ # Returns true if there is no more elements left in the queue.
165
+ #
181
166
  def empty?
182
- return @size.zero?
167
+ @que.empty?
183
168
  end
184
169
 
170
+ #
185
171
  # Remove all elements from the priority queue.
172
+ #
186
173
  def clear
187
- @qarray.replace([nil])
188
- @size = 0
189
- return self
174
+ @que.clear
175
+ self
190
176
  end
191
177
 
178
+ #
192
179
  # Replace the content of the heap by the new elements.
193
180
  #
194
- # The elements object must respond to #to_a, or to be a PQueue itself.
181
+ # The elements object must respond to #to_a, or to be
182
+ # a PQueue itself.
183
+ #
195
184
  def replace(elements)
196
185
  if elements.kind_of?(PQueue)
197
186
  initialize_copy(elements)
198
187
  else
199
- @qarray.replace([nil] + elements.to_a)
200
- @size = @qarray.size - 1
201
- heapify
188
+ @que.replace(elements.to_a)
189
+ sort!
202
190
  end
203
- return self
191
+ self
204
192
  end
205
193
 
194
+ #
206
195
  # Return a sorted array, with highest priority first.
196
+ #
207
197
  def to_a
208
- old_qarray = @qarray.dup
209
- old_size = @size
210
- res = pop_array
211
- @qarray = old_qarray
212
- @size = old_size
213
- return res
198
+ @que.dup
214
199
  end
215
200
 
216
- alias :sort :to_a
217
-
218
- # Replace the top element with the given one, and return this top element.
219
201
  #
220
- # Equivalent to successively calling #pop and #push(v).
221
- def replace_top(v)
222
- # replace top element
223
- if empty?
224
- @qarray[1] = v
225
- @size += 1
226
- return nil
227
- else
228
- res = @qarray[1]
229
- @qarray[1] = v
230
- downheap(1)
231
- return res
232
- end
233
- end
234
-
235
202
  # Return true if the given object is present in the queue.
203
+ #
236
204
  def include?(element)
237
- return @qarray.include?(element)
205
+ @que.include?(element)
206
+ end
207
+
208
+ #
209
+ # Push element onto queue while popping off and returning the next element.
210
+ # This is qquivalent to successively calling #pop and #push(v).
211
+ #
212
+ def swap(v)
213
+ r = pop
214
+ push(v)
215
+ r
238
216
  end
239
217
 
218
+ #
240
219
  # Iterate over the ordered elements, destructively.
220
+ #
241
221
  def each_pop #:yields: popped
242
222
  until empty?
243
223
  yield pop
244
224
  end
245
- return nil
225
+ nil
246
226
  end
247
227
 
248
- # Pretty print
228
+ #
229
+ # Pretty inspection string.
230
+ #
249
231
  def inspect
250
- "<#{self.class}: size=#{@size}, top=#{top || "nil"}>"
232
+ "<#{self.class}: size=#{size}, top=#{top || "nil"}>"
251
233
  end
252
234
 
253
- ###########################
254
- ### Override Object methods
255
-
235
+ #
256
236
  # Return true if the queues contain equal elements.
237
+ #
257
238
  def ==(other)
258
- return size == other.size && to_a == other.to_a
239
+ size == other.size && to_a == other.to_a
259
240
  end
260
241
 
261
- private
242
+ private
262
243
 
244
+ #
245
+ #
246
+ #
263
247
  def initialize_copy(other)
264
- @gt = other.gt
265
- @qarray = other.qarray.dup
266
- @size = other.size
248
+ @cmp = other.cmp
249
+ @que = other.que.dup
250
+ sort!
267
251
  end
268
- end # class PQueue
269
252
 
253
+ #
254
+ # The element at index k will be repositioned to its proper place.
255
+ #
256
+ # This, of course, assumes the queue is already sorted.
257
+ #
258
+ def reheap(k)
259
+ return self if size <= 1
260
+
261
+ que = @que.dup
262
+
263
+ v = que.delete_at(k)
264
+
265
+ i = que.size.div(2)
266
+ q = i
267
+ r = nil
268
+
269
+ loop do
270
+ case @cmp.call(v, que[i])
271
+ when 0, nil
272
+ r = i
273
+ break
274
+ when 1, true
275
+ i = (que.size + i).div(2)
276
+ i += 1 if i == q # don't repeat yourself
277
+ when -1, false
278
+ i = (i).div(2)
279
+ i -= 1 if i == q # don't repeat yourself
280
+ else
281
+ warn "bad comparison procedure in #{self.inspect}"
282
+ r = i
283
+ break
284
+ end
285
+ q = i
286
+ end
287
+
288
+ que.insert(r, v)
289
+
290
+ @que = que
291
+
292
+ return self
293
+ end
294
+
295
+ #
296
+ # Sort the queue in accorance to the given comparison procedure.
297
+ #
298
+ def sort!
299
+ @que.sort! do |a,b|
300
+ case @cmp.call(a,b)
301
+ when 0, nil then 0
302
+ when 1, true then 1
303
+ when -1, false then -1
304
+ else
305
+ warn "bad comparison procedure in #{self.inspect}"
306
+ 0
307
+ end
308
+ end
309
+ self
310
+ end
311
+
312
+ #
313
+ # Alias of #sort!
314
+ #
315
+ alias heapify sort!
316
+
317
+ end # class PQueue