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

priority_queue.hxx VIGRA

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
70 {
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>
233 : public BucketQueue<ValueType, Ascending>
234 {
235  PriorityFunctor get_priority_;
236 
237  public:
238 
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
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  */
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> >
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
bool empty() const
Queue contains no elements. Equivalent to size() == 0.
Definition: priority_queue.hxx:333
void clear()
check if the PQ is empty
Definition: priority_queue.hxx:449
bool empty() const
check if the PQ is empty
Definition: priority_queue.hxx:444
priority_type maxIndex() const
Maximum index (i.e. priority) allowed in this queue. Equivalent to bucket_count - 1...
Definition: priority_queue.hxx:109
Priority queue implemented using bucket sort.
Definition: priority_queue.hxx:69
size_type size() const
Number of elements in this queue.
Definition: priority_queue.hxx:93
priority_type topPriority() const
get top priority
Definition: priority_queue.hxx:496
void pop()
Remove the current top element.
Definition: priority_queue.hxx:502
Heap-based priority queue compatible to BucketQueue.
Definition: priority_queue.hxx:290
void push(value_type const &v)
Insert new element.
Definition: priority_queue.hxx:264
const_reference top() const
The current top element.
Definition: priority_queue.hxx:123
priority_type topPriority() const
Priority of the current top element.
Definition: priority_queue.hxx:348
bool contains(const int i) const
check if i is an index on the PQ
Definition: priority_queue.hxx:459
BucketQueue(size_type bucket_count=256)
Create bucket queue with.
Definition: priority_queue.hxx:86
MappedBucketQueue(unsigned int bucket_count=256, PriorityFunctor const &priority=PriorityFunctor())
Create a queue with.
Definition: priority_queue.hxx:251
void pop()
Remove the current top element.
Definition: priority_queue.hxx:363
void push(value_type const &v, priority_type priority)
Insert new element.
Definition: priority_queue.hxx:142
PriorityQueue()
Create empty priority queue.
Definition: priority_queue.hxx:319
int size() const
return the number of elements in the PQ
Definition: priority_queue.hxx:464
Definition: array_vector.hxx:58
Heap-based changable priority queue with a maximum number of elemements.
Definition: priority_queue.hxx:413
void push(const value_type i, const priority_type p)
Insert a index with a given priority.
Definition: priority_queue.hxx:475
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
reference front()
Definition: array_vector.hxx:307
priority_type topPriority() const
Priority of the current top element.
Definition: priority_queue.hxx:116
void pop()
Remove the current top element.
Definition: priority_queue.hxx:131
Priority queue implemented using bucket sort (STL compatible).
Definition: priority_queue.hxx:232
void push(value_type const &v, priority_type priority)
Insert new element.
Definition: priority_queue.hxx:370
bool empty() const
Queue contains no elements. Equivalent to size() == 0.
Definition: priority_queue.hxx:101
const_reference top() const
The current top element.
Definition: priority_queue.hxx:355
void deleteItem(const value_type i)
deleqte the priority associated with index i
Definition: priority_queue.hxx:516
ChangeablePriorityQueue(const size_t maxSize)
Create an empty ChangeablePriorityQueue which can contain atmost maxSize elements.
Definition: priority_queue.hxx:426
const_reference top() const
get index with top priority
Definition: priority_queue.hxx:490
priority_type maxIndex() const
Maximum index (i.e. priority) allowed in this queue. Equivalent to bucket_count - 1...
Definition: priority_queue.hxx:341
size_type size() const
Definition: array_vector.hxx:358
priority_type priority(const value_type i) const
returns the value associated with index i
Definition: priority_queue.hxx:511
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)