pqueue 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,269 @@
1
+ # PQueue, a Priority Queue with array based heap.
2
+ #
3
+ # A priority queue is like a standard queue, except that each inserted
4
+ # elements is given a certain priority, based on the result of the
5
+ # comparison block given at instantiation time. Also, retrieving an element
6
+ # from the queue will always return the one with the highest priority
7
+ # (see #pop and #top).
8
+ #
9
+ # The default is to compare the elements in repect to their #> method.
10
+ # For example, Numeric elements with higher values will have higher
11
+ # priorities.
12
+ #
13
+ class PQueue
14
+
15
+ # number of elements
16
+ attr_reader :size
17
+ # compare Proc
18
+ attr_reader :gt
19
+ attr_reader :qarray #:nodoc:
20
+ protected :qarray
21
+
22
+ # Returns a new priority queue.
23
+ #
24
+ # If elements are given, build the priority queue with these initial
25
+ # values. The elements object must respond to #to_a.
26
+ #
27
+ # If a block is given, it will be used to determine the priority between
28
+ # the elements.
29
+ #
30
+ # By default, the priority queue retrieves maximum elements first
31
+ # (using the #> method).
32
+ def initialize(elements=nil, &block) # :yields: a, b
33
+ @qarray = [nil]
34
+ @size = 0
35
+ @gt = block || lambda {|a,b| a > b}
36
+ replace(elements) if elements
37
+ end
38
+
39
+ private
40
+
41
+ # Assumes that the tree is a heap, for nodes < k.
42
+ #
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
54
+
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
73
+
74
+
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
106
+ end
107
+
108
+ public
109
+
110
+ # Add an element in the priority queue.
111
+ #
112
+ # The insertion time is O(log n), with n the size of the queue.
113
+ def push(v)
114
+ @size += 1
115
+ @qarray[@size] = v
116
+ upheap(@size)
117
+ return self
118
+ end
119
+
120
+ alias :<< :push
121
+
122
+ # Return the element with the highest priority and remove it from
123
+ # the queue.
124
+ #
125
+ # The highest priority is determined by the block given at instanciation
126
+ # time.
127
+ #
128
+ # The deletion time is O(log n), with n the size of the queue.
129
+ #
130
+ # Return nil if the queue is empty.
131
+ def pop
132
+ return nil if empty?
133
+ res = @qarray[1]
134
+ @qarray[1] = @qarray[@size]
135
+ @size -= 1
136
+ downheap(1)
137
+ return res
138
+ end
139
+
140
+ # Return the element with the highest priority.
141
+ def top
142
+ return nil if empty?
143
+ return @qarray[1]
144
+ end
145
+
146
+ # Add more than one element at the same time. See #push.
147
+ #
148
+ # The elements object must respond to #to_a, or to be a PQueue itself.
149
+ def push_all(elements)
150
+ if empty?
151
+ if elements.kind_of?(PQueue)
152
+ initialize_copy(elements)
153
+ else
154
+ replace(elements)
155
+ end
156
+ else
157
+ if elements.kind_of?(PQueue)
158
+ @qarray[@size + 1, elements.size] = elements.qarray[1..-1]
159
+ elements.size.times{ @size += 1; upheap(@size)}
160
+ else
161
+ ary = elements.to_a
162
+ @qarray[@size + 1, ary.size] = ary
163
+ ary.size.times{ @size += 1; upheap(@size)}
164
+ end
165
+ end
166
+ return self
167
+ end
168
+
169
+ alias :merge :push_all
170
+
171
+
172
+ # 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
177
+ end
178
+
179
+
180
+ # True if there is no more elements left in the priority queue.
181
+ def empty?
182
+ return @size.zero?
183
+ end
184
+
185
+ # Remove all elements from the priority queue.
186
+ def clear
187
+ @qarray.replace([nil])
188
+ @size = 0
189
+ return self
190
+ end
191
+
192
+ # Replace the content of the heap by the new elements.
193
+ #
194
+ # The elements object must respond to #to_a, or to be a PQueue itself.
195
+ def replace(elements)
196
+ if elements.kind_of?(PQueue)
197
+ initialize_copy(elements)
198
+ else
199
+ @qarray.replace([nil] + elements.to_a)
200
+ @size = @qarray.size - 1
201
+ heapify
202
+ end
203
+ return self
204
+ end
205
+
206
+ # Return a sorted array, with highest priority first.
207
+ 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
214
+ end
215
+
216
+ alias :sort :to_a
217
+
218
+ # Replace the top element with the given one, and return this top element.
219
+ #
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
+ # Return true if the given object is present in the queue.
236
+ def include?(element)
237
+ return @qarray.include?(element)
238
+ end
239
+
240
+ # Iterate over the ordered elements, destructively.
241
+ def each_pop #:yields: popped
242
+ until empty?
243
+ yield pop
244
+ end
245
+ return nil
246
+ end
247
+
248
+ # Pretty print
249
+ def inspect
250
+ "<#{self.class}: size=#{@size}, top=#{top || "nil"}>"
251
+ end
252
+
253
+ ###########################
254
+ ### Override Object methods
255
+
256
+ # Return true if the queues contain equal elements.
257
+ def ==(other)
258
+ return size == other.size && to_a == other.to_a
259
+ end
260
+
261
+ private
262
+
263
+ def initialize_copy(other)
264
+ @gt = other.gt
265
+ @qarray = other.qarray.dup
266
+ @size = other.size
267
+ end
268
+ end # class PQueue
269
+
@@ -1,17 +1,30 @@
1
+ require 'microtest'
2
+ require 'ae/legacy'
3
+
1
4
  require 'pqueue'
2
- require 'test/unit'
3
5
 
4
- class TC_PQueue < Test::Unit::TestCase
5
- ARY_TEST = [2,6,1,3,8,15,0,-4,7,8,10]
6
+ class TC_PQueue < MicroTest::TestCase
7
+ include AE::Legacy::Assertions
8
+
9
+ ARY_TEST = [2,6,1,3,8,15,0,-4,7,8,10]
6
10
  ARY_TEST_2 = [25,10,5,13,16,9,16,12]
7
11
 
8
- def test_initialize
9
- assert_nothing_raised { PQueue.new }
10
- assert_nothing_raised { PQueue.new([3]) }
11
- assert_nothing_raised { PQueue.new(ARY_TEST) }
12
- assert_nothing_raised { PQueue.new {|a,b| a<b} }
13
- assert_nothing_raised { PQueue.new([3]) {|a,b| a<b} }
14
- assert_nothing_raised { PQueue.new(ARY_TEST) {|a,b| a<b} }
12
+ def test_initialize_empty
13
+ PQueue.new
14
+ end
15
+
16
+ def test_initialize_single_element
17
+ PQueue.new([3])
18
+ end
19
+
20
+ def test_initialize_multiple_elements
21
+ PQueue.new(ARY_TEST)
22
+ end
23
+
24
+ def test_initialize_with_custom_comparison
25
+ PQueue.new {|a,b| b<=>a}
26
+ PQueue.new([3]) {|a,b| b<=>a}
27
+ PQueue.new(ARY_TEST) {|a,b| b<=>a}
15
28
  end
16
29
 
17
30
  def test_top
@@ -36,14 +49,18 @@ class TC_PQueue < Test::Unit::TestCase
36
49
  ret = q.push(24)
37
50
  assert_equal(q, ret)
38
51
  assert_equal(ARY_TEST.size+1, q.size)
52
+ end
53
+
54
+ def test_concat
55
+ q = PQueue.new(ARY_TEST)
39
56
 
40
- ret = q.push_all(ARY_TEST_2)
57
+ ret = q.concat(ARY_TEST_2)
41
58
  assert_equal(q, ret)
42
- assert_equal(ARY_TEST.size+1+ARY_TEST_2.size, q.size)
59
+ assert_equal(ARY_TEST.size+ARY_TEST_2.size, q.size)
43
60
 
44
61
  q = PQueue.new(ARY_TEST)
45
62
  r = PQueue.new(ARY_TEST_2)
46
- q.push_all(r)
63
+ q.concat(r)
47
64
  assert_equal(ARY_TEST.size + ARY_TEST_2.size, q.size)
48
65
  end
49
66
 
@@ -70,9 +87,9 @@ class TC_PQueue < Test::Unit::TestCase
70
87
 
71
88
  def test_to_a
72
89
  q = PQueue.new(ARY_TEST)
73
- assert_equal(ARY_TEST.sort.reverse, q.sort)
90
+ assert_equal(ARY_TEST.sort, q.to_a)
74
91
  q = PQueue.new(0..4)
75
- assert_equal([4,3,2,1,0], q.sort)
92
+ assert_equal([0,1,2,3,4], q.to_a)
76
93
  end
77
94
 
78
95
  def pop_array
@@ -90,20 +107,20 @@ class TC_PQueue < Test::Unit::TestCase
90
107
  assert_equal(false, q.include?(15))
91
108
  end
92
109
 
93
- def test_assert_equal
110
+ def test_equal
94
111
  assert_equal(PQueue.new, PQueue.new)
95
112
  assert_equal(PQueue.new(ARY_TEST), PQueue.new(ARY_TEST.sort_by{rand}))
96
113
  end
97
114
 
98
- def test_replace_top
115
+ def test_swap
99
116
  q = PQueue.new
100
- assert_nil(q.replace_top(6))
117
+ assert_nil(q.swap(6))
101
118
  assert_equal(6, q.top)
102
119
 
103
120
  q = PQueue.new(ARY_TEST)
104
121
  h = PQueue.new(ARY_TEST)
105
122
  q.pop; q.push(11)
106
- h.replace_top(11)
123
+ h.swap(11)
107
124
  assert_equal(q, h)
108
125
  end
109
126
 
@@ -126,7 +143,7 @@ class TC_PQueue < Test::Unit::TestCase
126
143
 
127
144
  ary = ARY_TEST.dup
128
145
  q = PQueue.new([1])
129
- q.push_all(ary)
146
+ q.concat(ary)
130
147
  q.pop
131
148
  assert_equal(ARY_TEST, ary)
132
149
 
metadata CHANGED
@@ -1,89 +1,99 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: pqueue
3
- version: !ruby/object:Gem::Version
4
- version: 1.0.0
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.0.0
5
+ prerelease:
5
6
  platform: ruby
6
- authors:
7
- - K.Kodama
7
+ authors:
8
+ - K. Kodama
8
9
  - Ronald Butler
9
10
  - Olivier Renaud
10
11
  - Rick Bradley
11
- - Trans <transfire@gmail.com>
12
+ - Thomas Sawyer
12
13
  autorequire:
13
14
  bindir: bin
14
15
  cert_chain: []
16
+ date: 2011-10-29 00:00:00.000000000 Z
17
+ dependencies:
18
+ - !ruby/object:Gem::Dependency
19
+ name: detroit
20
+ requirement: &27756040 !ruby/object:Gem::Requirement
21
+ none: false
22
+ requirements:
23
+ - - ! '>='
24
+ - !ruby/object:Gem::Version
25
+ version: '0'
26
+ type: :development
27
+ prerelease: false
28
+ version_requirements: *27756040
29
+ - !ruby/object:Gem::Dependency
30
+ name: microtest
31
+ requirement: &27755500 !ruby/object:Gem::Requirement
32
+ none: false
33
+ requirements:
34
+ - - ! '>='
35
+ - !ruby/object:Gem::Version
36
+ version: '0'
37
+ type: :development
38
+ prerelease: false
39
+ version_requirements: *27755500
40
+ - !ruby/object:Gem::Dependency
41
+ name: ae
42
+ requirement: &27755000 !ruby/object:Gem::Requirement
43
+ none: false
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: *27755000
51
+ description: ! 'A priority queue is like a standard queue, except that each inserted
52
+ elements
15
53
 
16
- date: 2009-07-05 00:00:00 -04:00
17
- default_executable:
18
- dependencies: []
54
+ is given a certain priority, based on the result of the comparison block given
19
55
 
20
- description: |-
21
- A priority queue is like a standard queue, except that each inserted
22
- elements is given a certain priority, based on the result of the
23
- comparison block given at instantiation time. Retrieving an element
24
- from the queue will always return the one with the highest priority.
25
- email:
26
- executables: []
56
+ at instantiation time. Retrieving an element from the queue will always return
27
57
 
58
+ the one with the highest priority.'
59
+ email:
60
+ - transfire@gmail.com
61
+ executables: []
28
62
  extensions: []
29
-
30
- extra_rdoc_files:
31
- - README
32
- - MANIFEST
33
- - RELEASE
34
- - LICENSE
35
- - HISTORY
36
- files:
37
- - test/test_pqueue.rb
38
- - RELEASE
39
- - LICENSE
40
- - README
41
- - HISTORY
42
- - meta/created
43
- - meta/repository
44
- - meta/homepage
45
- - meta/summary
46
- - meta/abstract
47
- - meta/package
48
- - meta/title
49
- - meta/released
50
- - meta/version
51
- - meta/license
52
- - meta/authors
53
- - meta/project
63
+ extra_rdoc_files:
64
+ - HISTORY.rdoc
65
+ - README.rdoc
66
+ - COPYING.rdoc
67
+ files:
68
+ - .ruby
69
+ - lib/pqueue/legacy.rb
54
70
  - lib/pqueue.rb
55
- - MANIFEST
56
- has_rdoc: true
57
- homepage: http://death.rubyforge.org/
71
+ - test/test_pqueue.rb
72
+ - HISTORY.rdoc
73
+ - README.rdoc
74
+ - COPYING.rdoc
75
+ homepage: http://rubyworks.github.com/pqueue
58
76
  licenses: []
59
-
60
77
  post_install_message:
61
- rdoc_options:
62
- - --inline-source
63
- - --title
64
- - pqueue api
65
- - --main
66
- - README
67
- require_paths:
78
+ rdoc_options: []
79
+ require_paths:
68
80
  - lib
69
- required_ruby_version: !ruby/object:Gem::Requirement
70
- requirements:
71
- - - ">="
72
- - !ruby/object:Gem::Version
73
- version: "0"
74
- version:
75
- required_rubygems_version: !ruby/object:Gem::Requirement
76
- requirements:
77
- - - ">="
78
- - !ruby/object:Gem::Version
79
- version: "0"
80
- version:
81
+ required_ruby_version: !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ! '>='
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
+ none: false
89
+ requirements:
90
+ - - ! '>='
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
81
93
  requirements: []
82
-
83
- rubyforge_project: death
84
- rubygems_version: 1.3.4
94
+ rubyforge_project:
95
+ rubygems_version: 1.8.10
85
96
  signing_key:
86
97
  specification_version: 3
87
- summary: A priority queue is like a standard queue, except that each inserted
88
- test_files:
89
- - test/test_pqueue.rb
98
+ summary: Queue of Prioritized Elements
99
+ test_files: []