[ VIGRA Homepage | Function Index | Class Index | Namespaces | File List | Main Page ]

priority_queue.hxx |

1 /************************************************************************/
2 /* */
3 /* Copyright 2010-2011 by Ullrich Koethe */
4 /* */
5 /* This file is part of the VIGRA computer vision library. */
6 /* The VIGRA Website is */
7 /* http://hci.iwr.uni-heidelberg.de/vigra/ */
8 /* Please direct questions, bug reports, and contributions to */
9 /* ullrich.koethe@iwr.uni-heidelberg.de or */
10 /* vigra@informatik.uni-hamburg.de */
11 /* */
12 /* Permission is hereby granted, free of charge, to any person */
13 /* obtaining a copy of this software and associated documentation */
14 /* files (the "Software"), to deal in the Software without */
15 /* restriction, including without limitation the rights to use, */
16 /* copy, modify, merge, publish, distribute, sublicense, and/or */
17 /* sell copies of the Software, and to permit persons to whom the */
18 /* Software is furnished to do so, subject to the following */
19 /* conditions: */
20 /* */
21 /* The above copyright notice and this permission notice shall be */
22 /* included in all copies or substantial portions of the */
23 /* Software. */
24 /* */
25 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */
26 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */
27 /* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
28 /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */
29 /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
30 /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
31 /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
32 /* OTHER DEALINGS IN THE SOFTWARE. */
33 /* */
34 /************************************************************************/
35
36
37 #ifndef VIGRA_PRIORITY_QUEUE_HXX
38 #define VIGRA_PRIORITY_QUEUE_HXX
39
40 #include "config.hxx"
41 #include "error.hxx"
42 #include "array_vector.hxx"
43 #include <queue>
44
45 namespace vigra {
46
47 /** \brief Priority queue implemented using bucket sort.
48
49 This template implements functionality similar to <tt><a href="http://www.sgi.com/tech/stl/priority_queue.html">std::priority_queue</a></tt>,
50 but uses a more efficient algorithm based on bucket sort. It can be used
51 when all priorities are positive integers in a given range (typically, 0...255).
52 By default, <tt>BucketQueue<ValueType></tt> sorts the elements in descending order,
53 i.e. like in <tt>std::priority_queue</tt> the largest element has highest priority.
54 An ascending queue can be specified as <tt>BucketQueue<ValueType, true></tt>.
55 Elements with equal priorities are returned in a first-in first-out fashion.
56
57 The main difference to <tt>std::priority_queue</tt> is the function <tt>push</tt>
58 which explicitly takes the priority of the element to be added as a second argument.
59 This allows optimization of <tt>ValueType</tt>: since the bucket uniquely
60 determines an element's priority, there is no need for <tt>ValueType</tt> to
61 store redundant priority information. If compatibility to <tt>std::priority_queue</tt>
62 is more important, use \ref vigra::MappedBucketQueue.
63
64 <b>\#include</b> <vigra/bucket_queue.hxx><br>
65 Namespace: vigra
66 */
67 template <class ValueType,
68 bool Ascending = false> // std::priority_queue is descending
69 class BucketQueue
70 {
71 ArrayVector<std::queue<ValueType> > buckets_;
72 std::size_t size_;
73 std::ptrdiff_t top_;
74
75 public:
76
77 typedef ValueType value_type;
78 typedef ValueType & reference;
79 typedef ValueType const & const_reference;
80 typedef std::size_t size_type;
81 typedef std::ptrdiff_t priority_type;
82
83 /** \brief Create bucket queue with \arg bucket_count entries.
84 Priorities must be integers in the range <tt>[0, ..., bucket_count-1]</tt>.
85 */
86 BucketQueue(size_type bucket_count = 256)
87 : buckets_(bucket_count),
88 size_(0), top_(0)
89 {}
90
91 /** \brief Number of elements in this queue.
92 */
93 size_type size() const
94 {
95 return size_;
96 }
97
98 /** \brief Queue contains no elements.
99 Equivalent to <tt>size() == 0</tt>.
100 */
101 bool empty() const
102 {
103 return size() == 0;
104 }
105
106 /** \brief Maximum index (i.e. priority) allowed in this queue.
107 Equivalent to <tt>bucket_count - 1</tt>.
108 */
109 priority_type maxIndex() const
110 {
111 return (priority_type)buckets_.size() - 1;
112 }
113
114 /** \brief Priority of the current top element.
115 */
116 priority_type topPriority() const
117 {
118 return top_;
119 }
120
121 /** \brief The current top element.
122 */
123 const_reference top() const
124 {
125
126 return buckets_[top_].front();
127 }
128
129 /** \brief Remove the current top element.
130 */
131 void pop()
132 {
133 --size_;
134 buckets_[top_].pop();
135
136 while(top_ > 0 && buckets_[top_].size() == 0)
137 --top_;
138 }
139
140 /** \brief Insert new element \arg v with given \arg priority.
141 */
142 void push(value_type const & v, priority_type priority)
143 {
144 ++size_;
145 buckets_[priority].push(v);
146
147 if(priority > top_)
148 top_ = priority;
149 }
150 };
151
152 template <class ValueType>
153 class BucketQueue<ValueType, true> // ascending queue
154 {
155 ArrayVector<std::queue<ValueType> > buckets_;
156 std::size_t size_;
157 std::ptrdiff_t top_;
158
159 public:
160
161 typedef ValueType value_type;
162 typedef ValueType & reference;
163 typedef ValueType const & const_reference;
164 typedef std::size_t size_type;
165 typedef std::ptrdiff_t priority_type;
166
167 BucketQueue(size_type bucket_count = 256)
168 : buckets_(bucket_count),
169 size_(0), top_((priority_type)bucket_count)
170 {}
171
172 size_type size() const
173 {
174 return size_;
175 }
176
177 bool empty() const
178 {
179 return size() == 0;
180 }
181
182 priority_type maxIndex() const
183 {
184 return (priority_type)buckets_.size() - 1;
185 }
186
187 priority_type topPriority() const
188 {
189 return top_;
190 }
191
192 const_reference top() const
193 {
194
195 return buckets_[top_].front();
196 }
197
198 void pop()
199 {
200 --size_;
201 buckets_[top_].pop();
202
203 while(top_ < (priority_type)buckets_.size() && buckets_[top_].size() == 0)
204 ++top_;
205 }
206
207 void push(value_type const & v, priority_type priority)
208 {
209 ++size_;
210 buckets_[priority].push(v);
211
212 if(priority < top_)
213 top_ = priority;
214 }
215 };
216
217 /** \brief Priority queue implemented using bucket sort (STL compatible).
218
219 This template is compatible to <tt><a href="http://www.sgi.com/tech/stl/priority_queue.html">std::priority_queue</a></tt>,
220 but uses a more efficient algorithm based on bucket sort. It us used
221 like \ref vigra::BucketQueue, but has an additional <tt>PriorityFunctor</tt>
222 which extracts the priority value of an element of type <tt>ValueType</tt>.
223 Thus functor is called within <tt>push</tt> so that it does not need an
224 extra argument.
225
226 <b>\#include</b> <vigra/priority_queue.hxx><br>
227 Namespace: vigra
228 */
229 template <class ValueType,
230 class PriorityFunctor,
231 bool Ascending = false>
232 class MappedBucketQueue
233 : public BucketQueue<ValueType, Ascending>
234 {
235 PriorityFunctor get_priority_;
236
237 public:
238
239 typedef BucketQueue<ValueType, Ascending> BaseType;
240 typedef typename BaseType::value_type value_type;
241 typedef typename BaseType::reference reference;
242 typedef typename BaseType::const_reference const_reference;
243 typedef typename BaseType::size_type size_type;
244 typedef typename BaseType::priority_type priority_type;
245
246 /** \brief Create a queue with \arg bucket_count entries.
247 Priorities will be computed by the <tt>PriorityFunctor</tt>
248 given in \arg priority (i.e. <tt>priority(v)</tt> must result in an integer,
249 where <tt>v</tt> is an instance of <tt>ValueType</tt>).
250 */
251 MappedBucketQueue(unsigned int bucket_count = 256,
252 PriorityFunctor const & priority = PriorityFunctor())
253 : BaseType(bucket_count),
254 get_priority_(priority)
255 {}
256
257 /** \brief Insert new element \arg v.
258 Its priority is calculated by <tt>priority(v)</tt>,
259 where <tt>priority</tt> is an instance of the
260 <tt>PriorityFunctor</tt> passed in the constructor.
261 If the priority is outside the range <tt>[0, ..., bucket_count-1]</tt>,
262 it is clamped to the range borders.
263 */
264 void push(value_type const & v)
265 {
266 priority_type index = get_priority_(v);
267
268 // clamp index to the allowed range
269 if(index > BaseType::maxIndex())
270 index = BaseType::maxIndex();
271 else if (index < 0)
272 index = 0;
273
274 BaseType::push(v, index);
275 }
276 };
277
278 /** \brief Heap-based priority queue compatible to BucketQueue.
279
280 This template is compatible to \ref vigra::BucketQueue, but accepts arbitrary priority
281 types. Internally, it uses a <tt>std::priority_queue</tt>, but implements an
282 API where priorities and payload data are separate, like in \ref vigra::BucketQueue.
283
284 <b>\#include</b> <vigra/priority_queue.hxx><br>
285 Namespace: vigra
286 */
287 template <class ValueType,
288 class PriorityType,
289 bool Ascending = false> // std::priority_queue is descending
290 class PriorityQueue
291 {
292 typedef std::pair<ValueType, PriorityType> ElementType;
293
294 struct Compare
295 {
296 typename IfBool<Ascending, std::greater<PriorityType>,
297 std::less<PriorityType> >::type cmp;
298
299 bool operator()(ElementType const & l, ElementType const & r) const
300 {
301 return cmp(l.second, r.second);
302 }
303 };
304
305 typedef std::priority_queue<ElementType, std::vector<ElementType>, Compare> Heap;
306
307 Heap heap_;
308
309 public:
310
311 typedef ValueType value_type;
312 typedef ValueType & reference;
313 typedef ValueType const & const_reference;
314 typedef typename Heap::size_type size_type;
315 typedef PriorityType priority_type;
316
317 /** \brief Create empty priority queue.
318 */
319 PriorityQueue()
320 : heap_()
321 {}
322
323 /** \brief Number of elements in this queue.
324 */
325 size_type size() const
326 {
327 return heap_.size();
328 }
329
330 /** \brief Queue contains no elements.
331 Equivalent to <tt>size() == 0</tt>.
332 */
333 bool empty() const
334 {
335 return size() == 0;
336 }
337
338 /** \brief Maximum index (i.e. priority) allowed in this queue.
339 Equivalent to <tt>bucket_count - 1</tt>.
340 */
341 priority_type maxIndex() const
342 {
343 return NumericTraits<priority_type>::max();
344 }
345
346 /** \brief Priority of the current top element.
347 */
348 priority_type topPriority() const
349 {
350 return heap_.top().second;
351 }
352
353 /** \brief The current top element.
354 */
355 const_reference top() const
356 {
357
358 return heap_.top().first;
359 }
360
361 /** \brief Remove the current top element.
362 */
363 void pop()
364 {
365 heap_.pop();
366 }
367
368 /** \brief Insert new element \arg v with given \arg priority.
369 */
370 void push(value_type const & v, priority_type priority)
371 {
372 heap_.push(ElementType(v, priority));
373 }
374 };
375
376 template <class ValueType,
377 bool Ascending>
378 class PriorityQueue<ValueType, unsigned char, Ascending>
379 : public BucketQueue<ValueType, Ascending>
380 {
381 public:
382 typedef BucketQueue<ValueType, Ascending> BaseType;
383
384 PriorityQueue()
385 : BaseType(NumericTraits<unsigned char>::max()+1)
386 {}
387 };
388
389 template <class ValueType,
390 bool Ascending>
391 class PriorityQueue<ValueType, unsigned short, Ascending>
392 : public BucketQueue<ValueType, Ascending>
393 {
394 public:
395 typedef BucketQueue<ValueType, Ascending> BaseType;
396
397 PriorityQueue()
398 : BaseType(NumericTraits<unsigned short>::max()+1)
399 {}
400 };
401
402
403
404 /** \brief Heap-based changable priority queue with a maximum number of elemements.
405
406 This pq allows to change the priorities of elements in the queue
407
408 <b>\#include</b> <vigra/priority_queue.hxx><br>
409
410 Namespace: vigra
411 */
412 template<class T,class COMPARE = std::less<T> >
413 class ChangeablePriorityQueue {
414
415
416 public:
417
418 typedef T priority_type;
419 typedef int ValueType;
420 typedef ValueType value_type;
421 typedef ValueType const_reference;
422
423
424
425 /// Create an empty ChangeablePriorityQueue which can contain atmost maxSize elements
426 ChangeablePriorityQueue(const size_t maxSize)
427 : maxSize_(maxSize),
428 currentSize_(0),
429 heap_(maxSize_+1),
430 indices_(maxSize_+1, -1),
431 priorities_(maxSize_+1)
432 {
433 for(unsigned i = 0; i <= maxSize_; i++)
434 indices_[i] = -1;
435 }
436
437
438 void reset(){
439 currentSize_ = 0 ;
440 for(int i = 0; i <= maxSize_; i++)
441 indices_[i] = -1;
442 }
443 /// check if the PQ is empty
444 bool empty() const {
445 return currentSize_ == 0;
446 }
447
448 /// check if the PQ is empty
449 void clear() {
450 for(int i = 0; i < currentSize_; i++)
451 {
452 indices_[heap_[i+1]] = -1;
453 heap_[i+1] = -1;
454 }
455 currentSize_ = 0;
456 }
457
458 /// check if i is an index on the PQ
459 bool contains(const int i) const{
460 return indices_[i] != -1;
461 }
462
463 /// return the number of elements in the PQ
464 int size()const{
465 return currentSize_;
466 }
467
468
469 /** \brief Insert a index with a given priority.
470
471 If the queue contains i bevore this
472 call the priority of the given index will
473 be changed
474 */
475 void push(const value_type i, const priority_type p) {
476 if(!contains(i)){
477 currentSize_++;
478 indices_[i] = currentSize_;
479 heap_[currentSize_] = i;
480 priorities_[i] = p;
481 bubbleUp(currentSize_);
482 }
483 else{
484 changePriority(i,p);
485 }
486 }
487
488 /** \brief get index with top priority
489 */
490 const_reference top() const {
491 return heap_[1];
492 }
493
494 /**\brief get top priority
495 */
496 priority_type topPriority() const {
497 return priorities_[heap_[1]];
498 }
499
500 /** \brief Remove the current top element.
501 */
502 void pop() {
503 const int min = heap_[1];
504 swapItems(1, currentSize_--);
505 bubbleDown(1);
506 indices_[min] = -1;
507 heap_[currentSize_+1] = -1;
508 }
509
510 /// returns the value associated with index i
511 priority_type priority(const value_type i) const{
512 return priorities_[i];
513 }
514
515 /// deleqte the priority associated with index i
516 void deleteItem(const value_type i) {
517 int ind = indices_[i];
518 swapItems(ind, currentSize_--);
519 bubbleUp(ind);
520 bubbleDown(ind);
521 indices_[i] = -1;
522 }
523 /** \brief change priority of a given index.
524 The index must be in the queue!
525 Call push to auto insert / change .
526 */
527 void changePriority(const value_type i,const priority_type p) {
528 if(_gt(p,priorities_[i])){
529 priorities_[i] = p;
530 bubbleDown(indices_[i]);
531 }
532 else if(_lt(p,priorities_[i])) {
533 priorities_[i] = p;
534 bubbleUp(indices_[i]);
535 }
536 }
537 private:
538
539
540 void swapItems(const int i,const int j) {
541 std::swap(heap_[i],heap_[j]);
542 indices_[heap_[i]] = i;
543 indices_[heap_[j]] = j;
544 }
545
546 void bubbleUp(int k) {
547 while(k > 1 && _gt( priorities_[heap_[k/2]],priorities_[heap_[k]])) {
548 swapItems(k, k/2);
549 k = k/2;
550 }
551 }
552
553 void bubbleDown(int k) {
554 int j;
555 while(static_cast<unsigned>(2*k) <= currentSize_) {
556 j = 2*k;
557 if(static_cast<unsigned>(j) < currentSize_ && _gt(priorities_[heap_[j]] , priorities_[heap_[j+1]]) )
558 j++;
559 if( _leqt(priorities_[heap_[k]] , priorities_[heap_[j]]))
560 break;
561 swapItems(k, j);
562 k = j;
563 }
564 }
565
566
567 bool _lt(const T & a,const T & b)const{
568 return comp_(a,b);
569 }
570 bool _leqt(const T & a,const T & b)const{
571 return !comp_(b,a);
572 }
573 bool _eq(const T & a,const T & b)const{
574 return !comp_(a,b) && !comp_(b,a);
575 }
576 bool _gt(const T & a,const T & b)const{
577 return !_eq(a,b) && !comp_(a,b);
578 }
579 bool _geqt(const T & a,const T & b)const{
580 return !comp_(a,b);
581 }
582
583
584 size_t maxSize_;
585 size_t currentSize_;
586 std::vector<int> heap_;
587 std::vector<int> indices_;
588 std::vector<T> priorities_;
589 COMPARE comp_;
590
591 };
592
593
594 } // namespace vigra
595
596 #endif // VIGRA_PRIORITY_QUEUE_HXX
vigra::PriorityQueue::empty
bool empty() const
Queue contains no elements. Equivalent to size() == 0.
Definition: priority_queue.hxx:333
vigra::ChangeablePriorityQueue::clear
void clear()
check if the PQ is empty
Definition: priority_queue.hxx:449
vigra::ChangeablePriorityQueue::empty
bool empty() const
check if the PQ is empty
Definition: priority_queue.hxx:444
vigra::BucketQueue::maxIndex
priority_type maxIndex() const
Maximum index (i.e. priority) allowed in this queue. Equivalent to bucket_count - 1...
Definition: priority_queue.hxx:109
vigra::BucketQueue
Priority queue implemented using bucket sort.
Definition: priority_queue.hxx:69
vigra::BucketQueue::size
size_type size() const
Number of elements in this queue.
Definition: priority_queue.hxx:93
vigra::ChangeablePriorityQueue::topPriority
priority_type topPriority() const
get top priority
Definition: priority_queue.hxx:496
vigra::ChangeablePriorityQueue::pop
void pop()
Remove the current top element.
Definition: priority_queue.hxx:502
vigra::PriorityQueue
Heap-based priority queue compatible to BucketQueue.
Definition: priority_queue.hxx:290
vigra::MappedBucketQueue::push
void push(value_type const &v)
Insert new element.
Definition: priority_queue.hxx:264
vigra::BucketQueue::top
const_reference top() const
The current top element.
Definition: priority_queue.hxx:123
vigra::PriorityQueue::topPriority
priority_type topPriority() const
Priority of the current top element.
Definition: priority_queue.hxx:348
vigra::ChangeablePriorityQueue::contains
bool contains(const int i) const
check if i is an index on the PQ
Definition: priority_queue.hxx:459
vigra::BucketQueue::BucketQueue
BucketQueue(size_type bucket_count=256)
Create bucket queue with.
Definition: priority_queue.hxx:86
vigra::MappedBucketQueue::MappedBucketQueue
MappedBucketQueue(unsigned int bucket_count=256, PriorityFunctor const &priority=PriorityFunctor())
Create a queue with.
Definition: priority_queue.hxx:251
vigra::PriorityQueue::pop
void pop()
Remove the current top element.
Definition: priority_queue.hxx:363
vigra::BucketQueue::push
void push(value_type const &v, priority_type priority)
Insert new element.
Definition: priority_queue.hxx:142
vigra::PriorityQueue::PriorityQueue
PriorityQueue()
Create empty priority queue.
Definition: priority_queue.hxx:319
vigra::ChangeablePriorityQueue::size
int size() const
return the number of elements in the PQ
Definition: priority_queue.hxx:464
vigra::ArrayVector
Definition: array_vector.hxx:58
vigra::ChangeablePriorityQueue
Heap-based changable priority queue with a maximum number of elemements.
Definition: priority_queue.hxx:413
vigra::ChangeablePriorityQueue::push
void push(const value_type i, const priority_type p)
Insert a index with a given priority.
Definition: priority_queue.hxx:475
vigra::ChangeablePriorityQueue::changePriority
void changePriority(const value_type i, const priority_type p)
change priority of a given index. The index must be in the queue! Call push to auto insert / change ...
Definition: priority_queue.hxx:527
vigra::ArrayVectorView::front
reference front()
Definition: array_vector.hxx:307
vigra::BucketQueue::topPriority
priority_type topPriority() const
Priority of the current top element.
Definition: priority_queue.hxx:116
vigra::BucketQueue::pop
void pop()
Remove the current top element.
Definition: priority_queue.hxx:131
vigra::MappedBucketQueue
Priority queue implemented using bucket sort (STL compatible).
Definition: priority_queue.hxx:232
vigra::PriorityQueue::push
void push(value_type const &v, priority_type priority)
Insert new element.
Definition: priority_queue.hxx:370
vigra::BucketQueue::empty
bool empty() const
Queue contains no elements. Equivalent to size() == 0.
Definition: priority_queue.hxx:101
vigra::PriorityQueue::top
const_reference top() const
The current top element.
Definition: priority_queue.hxx:355
vigra::ChangeablePriorityQueue::deleteItem
void deleteItem(const value_type i)
deleqte the priority associated with index i
Definition: priority_queue.hxx:516
vigra::ChangeablePriorityQueue::ChangeablePriorityQueue
ChangeablePriorityQueue(const size_t maxSize)
Create an empty ChangeablePriorityQueue which can contain atmost maxSize elements.
Definition: priority_queue.hxx:426
vigra::ChangeablePriorityQueue::top
const_reference top() const
get index with top priority
Definition: priority_queue.hxx:490
vigra::PriorityQueue::maxIndex
priority_type maxIndex() const
Maximum index (i.e. priority) allowed in this queue. Equivalent to bucket_count - 1...
Definition: priority_queue.hxx:341
vigra::ArrayVectorView::size
size_type size() const
Definition: array_vector.hxx:358
vigra::ChangeablePriorityQueue::priority
priority_type priority(const value_type i) const
returns the value associated with index i
Definition: priority_queue.hxx:511
vigra::PriorityQueue::size
size_type size() const
Number of elements in this queue.
Definition: priority_queue.hxx:325

© Ullrich Köthe (ullrich.koethe@iwr.uni-heidelberg.de) Heidelberg Collaboratory for Image Processing, University of Heidelberg, Germany | html generated using doxygen and Python vigra 1.11.1 (Fri May 19 2017)