aGrUM  0.16.0
multiPriorityQueue_tpl.h
Go to the documentation of this file.
1 
30 // to help IDE parser
32 
33 namespace gum {
34 
35  // basic constructor
36  template < typename Val, typename Priority, typename Cmp, typename Alloc >
38  Cmp compare, Size capacity) :
39  __indices(capacity >> 1, true, false),
40  __cmp(compare) {
41  __heap.reserve(capacity);
42 
43  // for debugging purposes
44  GUM_CONSTRUCTOR(MultiPriorityQueue);
45  }
46 
47  // initializer list constructor
48  template < typename Val, typename Priority, typename Cmp, typename Alloc >
50  std::initializer_list< std::pair< Val, Priority > > list) :
51  __indices(Size(list.size()) / 2, true, false) {
52  // fill the queue
53  __heap.reserve(list.size());
54  for (const auto& elt : list) {
55  insert(elt.first, elt.second);
56  }
57 
58  // for debugging purposes
59  GUM_CONSTRUCTOR(MultiPriorityQueue);
60  }
61 
62  // copy constructor
63  template < typename Val, typename Priority, typename Cmp, typename Alloc >
66  __heap(from.__heap),
67  __indices(from.__indices), __nb_elements(from.__nb_elements),
68  __cmp(from.__cmp) {
69  // for debugging purposes
70  GUM_CONS_CPY(MultiPriorityQueue);
71 
72  // fill the heap structure
73  for (const auto& val_and_index : __indices) {
74  const Val* val = &(val_and_index.first);
75  const std::vector< Size >& vect = val_and_index.second;
76  for (auto index : vect) {
77  __heap[index].second = val;
78  }
79  }
80  }
81 
82  // generalized copy constructor
83  template < typename Val, typename Priority, typename Cmp, typename Alloc >
84  template < typename OtherAlloc >
87  __indices(from.__indices),
88  __nb_elements(from.__nb_elements), __cmp(from.__cmp) {
89  // for debugging purposes
90  GUM_CONS_CPY(MultiPriorityQueue);
91 
92  // fill the heap structure
93  if (__nb_elements) {
94  __heap.reserve(from.__heap.size());
95  for (const auto& elt : from.__heap) {
96  __heap.push_back(elt);
97  }
98  for (const auto& val_and_index : __indices) {
99  const Val* val = &(val_and_index.first);
100  const std::vector< Size >& vect = val_and_index.second;
101  for (auto index : vect) {
102  __heap[index].second = val;
103  }
104  }
105  }
106  }
107 
108  // move constructor
109  template < typename Val, typename Priority, typename Cmp, typename Alloc >
112  __heap(std::move(from.__heap)),
113  __indices(std::move(from.__indices)),
114  __nb_elements(std::move(from.__nb_elements)), __cmp(std::move(from.__cmp)) {
115  // for debugging purposes
116  GUM_CONS_MOV(MultiPriorityQueue);
117  }
118 
119  // destructor
120  template < typename Val, typename Priority, typename Cmp, typename Alloc >
122  // for debugging purposes
123  GUM_DESTRUCTOR(MultiPriorityQueue);
124  }
125 
126  // copy operator
127  template < typename Val, typename Priority, typename Cmp, typename Alloc >
131  // for debugging purposes
132  GUM_OP_CPY(MultiPriorityQueue);
133 
134  try {
135  // set the comprison function
136  __cmp = from.__cmp;
137 
138  // copy the indices and the heap
139  __indices = from.__indices;
140  __heap = from.__heap;
141  __nb_elements = from.__nb_elements;
142 
143  // restore the link between __indices and __heap
144  for (const auto& val_and_index : __indices) {
145  const Val* val = &(val_and_index.first);
146  const std::vector< Size >& vect = val_and_index.second;
147  for (auto index : vect) {
148  __heap[index].second = val;
149  }
150  }
151  } catch (...) {
152  __heap.clear();
153  __indices.clear();
154  __nb_elements = 0;
155 
156  throw;
157  }
158 
159  return *this;
160  }
161 
162  // generalized copy operator
163  template < typename Val, typename Priority, typename Cmp, typename Alloc >
164  template < typename OtherAlloc >
168  // for debugging purposes
169  GUM_OP_CPY(MultiPriorityQueue);
170 
171  try {
172  // set the comprison function
173  __cmp = from.__cmp;
174 
175  // copy the indices and the heap
176  __indices = from.__indices;
177  __nb_elements = from.__nb_elements;
178 
179  // restore the link between __indices and __heap
180  __heap.clear();
181  __heap.reserve(from.__heap.size());
182  for (const auto& elt : from.__heap) {
183  __heap.push_back(elt);
184  }
185  for (const auto& val_and_index : __indices) {
186  const Val* val = &(val_and_index.first);
187  const std::vector< Size >& vect = val_and_index.second;
188  for (auto index : vect) {
189  __heap[index].second = val;
190  }
191  }
192  } catch (...) {
193  __heap.clear();
194  __indices.clear();
195  __nb_elements = 0;
196 
197  throw;
198  }
199 
200  return *this;
201  }
202 
203  // move operator
204  template < typename Val, typename Priority, typename Cmp, typename Alloc >
208  // avoid self assignment
209  if (this != &from) {
210  // for debugging purposes
211  GUM_OP_MOV(MultiPriorityQueue);
212 
213  __cmp = std::move(from.__cmp);
214  __indices = std::move(from.__indices);
215  __heap = std::move(from.__heap);
216  __nb_elements = std::move(from.__nb_elements);
217  }
218 
219  return *this;
220  }
221 
222  // returns the element at the top of the priority queue
223  template < typename Val, typename Priority, typename Cmp, typename Alloc >
225  if (!__nb_elements) { GUM_ERROR(NotFound, "empty priority queue"); }
226 
227  return *(__heap[0].second);
228  }
229 
230  // returns the priority of the top element
231  template < typename Val, typename Priority, typename Cmp, typename Alloc >
232  INLINE const Priority&
234  if (!__nb_elements) { GUM_ERROR(NotFound, "empty priority queue"); }
235 
236  return __heap[0].first;
237  }
238 
239  // returns the number of elements in the priority queue
240  template < typename Val, typename Priority, typename Cmp, typename Alloc >
242  noexcept {
243  return __nb_elements;
244  }
245 
246  // return the size of the array storing the priority queue
247  template < typename Val, typename Priority, typename Cmp, typename Alloc >
249  noexcept {
250  return Size(__heap.capacity());
251  }
252 
253  // changes the size of the array storing the priority queue
254  template < typename Val, typename Priority, typename Cmp, typename Alloc >
255  INLINE void
257  if (new_size < __nb_elements) return;
258 
259  __heap.reserve(new_size);
260  __indices.resize(new_size / 2);
261  }
262 
263  // removes all the elements from the queue
264  template < typename Val, typename Priority, typename Cmp, typename Alloc >
266  __nb_elements = 0;
267  __heap.clear();
268  __indices.clear();
269  }
270 
271  // removes the element at index elt from the priority queue
272  template < typename Val, typename Priority, typename Cmp, typename Alloc >
274  if (index >= __nb_elements) return;
275 
276  // remove the element from the hashtable
277  const Val& del_val = *(__heap[index].second);
278  std::vector< Size >& vect_index = __indices[del_val];
279  if (vect_index.size() == 1)
280  __indices.erase(del_val);
281  else {
282  for (auto& v_index : vect_index) {
283  if (v_index == index) {
284  v_index = vect_index.back();
285  vect_index.pop_back();
286  break;
287  }
288  }
289  }
290 
291  // put the last element at the "index" location
292  std::pair< Priority, const Val* > last = std::move(__heap.back());
293  __heap.pop_back();
294  --__nb_elements;
295 
296  if (!__nb_elements || (index == __nb_elements)) return;
297 
298  // restore the heap property
299  Size i = index;
300 
301  for (Size j = (index << 1) + 1; j < __nb_elements; i = j, j = (j << 1) + 1) {
302  // let j be the max child
303  if ((j + 1 < __nb_elements) && __cmp(__heap[j + 1].first, __heap[j].first))
304  ++j;
305 
306  // if "last" is lower than heap[j], "last" must be stored at index i
307  if (__cmp(last.first, __heap[j].first)) break;
308 
309  // else pull up the jth node
310  __heap[i] = std::move(__heap[j]);
311  std::vector< Size >& vect_index = __indices[*(__heap[i].second)];
312  for (auto& v_index : vect_index) {
313  if (v_index == j) {
314  v_index = i;
315  break;
316  }
317  }
318  }
319 
320  // put "last" back into the heap
321  __heap[i] = std::move(last);
322  std::vector< Size >& last_indices = __indices[*(__heap[i].second)];
323  for (auto& v_index : last_indices) {
324  if (v_index == __nb_elements) {
325  v_index = i;
326  break;
327  }
328  }
329  }
330 
331  // removes a given element from the priority queue (but does not return it)
332  template < typename Val, typename Priority, typename Cmp, typename Alloc >
333  INLINE void
335  try {
336  eraseByPos(__indices[val][0]);
337  } catch (NotFound&) {}
338  }
339 
340  // removes the top of the priority queue (but does not return it)
341  template < typename Val, typename Priority, typename Cmp, typename Alloc >
343  eraseByPos(0);
344  }
345 
346  // removes the top element from the priority queue and return it
347  template < typename Val, typename Priority, typename Cmp, typename Alloc >
349  if (!__nb_elements) { GUM_ERROR(NotFound, "empty priority queue"); }
350 
351  Val v = *(__heap[0].second);
352  eraseByPos(0);
353 
354  return v;
355  }
356 
357  // returns a hashtable the keys of which are the values stored in the queue
358  template < typename Val, typename Priority, typename Cmp, typename Alloc >
361  return reinterpret_cast< const HashTable< Val, std::vector< Size > >& >(
362  __indices);
363  }
364 
365  // inserts a new (a copy) element in the priority queue
366  template < typename Val, typename Priority, typename Cmp, typename Alloc >
368  const Val& val, const Priority& priority) {
369  // create the entry in the indices hashtable
370  const Val* new_val;
371  std::vector< Size >* new_vect;
372  if (!__indices.exists(val)) {
373  auto& new_elt = __indices.insert(val, std::vector< Size >());
374  new_val = &(new_elt.first);
375  new_vect = &(new_elt.second);
376  } else {
377  new_val = &(__indices.key(val));
378  new_vect = &(__indices[val]);
379  }
380 
381  try {
382  new_vect->push_back(0);
383  } catch (...) {
384  if (new_vect->empty()) { __indices.erase(val); }
385  throw;
386  }
387 
388  try {
389  __heap.push_back(std::pair< Priority, const Val* >(priority, new_val));
390  } catch (...) {
391  if (new_vect->size() == 1) { __indices.erase(val); }
392  throw;
393  }
394 
395  std::pair< Priority, const Val* > new_heap_val =
396  std::move(__heap[__nb_elements]);
397  ++__nb_elements;
398 
399  // restore the heap property
400  Size i = __nb_elements - 1;
401 
402  for (Size j = (i - 1) >> 1; i && __cmp(new_heap_val.first, __heap[j].first);
403  i = j, j = (j - 1) >> 1) {
404  __heap[i] = std::move(__heap[j]);
405  std::vector< Size >& vect_index = __indices[*(__heap[i].second)];
406  for (auto& index : vect_index) {
407  if (index == j) {
408  index = i;
409  break;
410  }
411  }
412  }
413 
414  // put the new bucket into the heap
415  __heap[i].first = std::move(new_heap_val.first);
416  __heap[i].second = new_val;
417  new_vect->back() = i;
418 
419  return i;
420  }
421 
422  // inserts a new (a copy) element in the priority queue
423  template < typename Val, typename Priority, typename Cmp, typename Alloc >
424  Size
426  Priority&& priority) {
427  // create the entry in the indices hashtable
428  const Val* new_val;
429  std::vector< Size >* new_vect;
430  if (!__indices.exists(val)) {
431  auto& new_elt = __indices.insert(std::move(val), std::vector< Size >());
432  new_val = &(new_elt.first);
433  new_vect = &(new_elt.second);
434  } else {
435  new_val = &(__indices.key(val));
436  new_vect = &(__indices[val]);
437  }
438 
439  try {
440  new_vect->push_back(0);
441  } catch (...) {
442  if (new_vect->empty()) { __indices.erase(*new_val); }
443  throw;
444  }
445 
446  try {
447  __heap.push_back(
448  std::pair< Priority, const Val* >(std::move(priority), new_val));
449  } catch (...) {
450  if (new_vect->size() == 1) { __indices.erase(*new_val); }
451  throw;
452  }
453 
454  std::pair< Priority, const Val* > new_heap_val =
455  std::move(__heap[__nb_elements]);
456  ++__nb_elements;
457 
458  // restore the heap property
459  Size i = __nb_elements - 1;
460 
461  for (Size j = (i - 1) >> 1; i && __cmp(new_heap_val.first, __heap[j].first);
462  i = j, j = (j - 1) >> 1) {
463  __heap[i] = std::move(__heap[j]);
464  std::vector< Size >& vect_index = __indices[*(__heap[i].second)];
465  for (auto& index : vect_index) {
466  if (index == j) {
467  index = i;
468  break;
469  }
470  }
471  }
472 
473  // put the new bucket into the heap
474  __heap[i].first = std::move(new_heap_val.first);
475  __heap[i].second = new_val;
476  new_vect->back() = i;
477 
478  return i;
479  }
480 
481  // emplace a new element into the priority queue
482  template < typename Val, typename Priority, typename Cmp, typename Alloc >
483  template < typename... Args >
484  INLINE Size
486  std::pair< Val, Priority > new_elt =
487  std::make_pair< Val, Priority >(std::forward< Args >(args)...);
488  return insert(std::move(new_elt.first), std::move(new_elt.second));
489  }
490 
491  // indicates whether the priority queue is empty
492  template < typename Val, typename Priority, typename Cmp, typename Alloc >
494  noexcept {
495  return (__nb_elements == 0);
496  }
497 
498  // indicates whether the priority queue contains a given value
499  template < typename Val, typename Priority, typename Cmp, typename Alloc >
501  const Val& val) const {
502  return __indices.exists(val);
503  }
504 
505  // returns the element at position "index" in the priority queue
506  template < typename Val, typename Priority, typename Cmp, typename Alloc >
508  operator[](Size index) const {
509  if (index >= __nb_elements) {
510  GUM_ERROR(NotFound, "not enough elements in the MultiPriorityQueue");
511  }
512 
513  return *(__heap[index].second);
514  }
515 
516  // displays the content of the queue
517  template < typename Val, typename Priority, typename Cmp, typename Alloc >
519  bool deja = false;
520  std::stringstream stream;
521  stream << "[";
522 
523  for (Size i = 0; i != __nb_elements; ++i, deja = true) {
524  if (deja) stream << " , ";
525 
526  stream << "(" << __heap[i].first << " , " << *(__heap[i].second) << ")";
527  }
528 
529  stream << "]";
530 
531  return stream.str();
532  }
533 
534  // changes the size of the internal structure storing the priority queue
535  template < typename Val, typename Priority, typename Cmp, typename Alloc >
537  Size index, const Priority& new_priority) {
538  // check whether the element the priority of which should be changed exists
539  if (index >= __nb_elements) {
540  GUM_ERROR(NotFound, "not enough elements in the MultiPriorityQueue");
541  }
542 
543  // get the element itself
544  const Val* val = __heap[index].second;
545 
546  // restore the heap property
547  Size i = index;
548 
549  // move val upward if needed
550  for (Size j = (i - 1) >> 1; i && __cmp(new_priority, __heap[j].first);
551  i = j, j = (j - 1) >> 1) {
552  __heap[i] = std::move(__heap[j]);
553  std::vector< Size >& vect_index = __indices[*(__heap[i].second)];
554  for (auto& idx : vect_index) {
555  if (idx == j) {
556  idx = i;
557  break;
558  }
559  }
560  }
561 
562  // move val downward if needed
563  for (Size j = (i << 1) + 1; j < __nb_elements; i = j, j = (j << 1) + 1) {
564  // let j be the max child
565  if ((j + 1 < __nb_elements) && __cmp(__heap[j + 1].first, __heap[j].first))
566  ++j;
567 
568  // if "val" is lower than heap[j], "val" must be stored at index i
569  if (__cmp(new_priority, __heap[j].first)) break;
570 
571  // else pull up the jth node
572  __heap[i] = std::move(__heap[j]);
573  std::vector< Size >& vect_index = __indices[*(__heap[i].second)];
574  for (auto& idx : vect_index) {
575  if (idx == j) {
576  idx = i;
577  break;
578  }
579  }
580  }
581 
582  // update the index of val
583  __heap[i].first = new_priority;
584  __heap[i].second = val;
585  std::vector< Size >& vect_index = __indices[*(__heap[i].second)];
586  for (auto& idx : vect_index) {
587  if (idx == index) {
588  idx = i;
589  break;
590  }
591  }
592 
593  return i;
594  }
595 
596  // changes the size of the internal structure storing the priority queue
597  template < typename Val, typename Priority, typename Cmp, typename Alloc >
599  Size index, Priority&& new_priority) {
600  // check whether the element the priority of which should be changed exists
601  if (index >= __nb_elements) {
602  GUM_ERROR(NotFound, "not enough elements in the MultiPriorityQueue");
603  }
604 
605  // get the element itself
606  const Val* val = __heap[index].second;
607 
608  // restore the heap property
609  Size i = index;
610 
611  // move val upward if needed
612  for (Size j = (i - 1) >> 1; i && __cmp(new_priority, __heap[j].first);
613  i = j, j = (j - 1) >> 1) {
614  __heap[i] = std::move(__heap[j]);
615  std::vector< Size >& vect_index = __indices[*(__heap[i].second)];
616  for (auto& idx : vect_index) {
617  if (idx == j) {
618  idx = i;
619  break;
620  }
621  }
622  }
623 
624  // move val downward if needed
625  for (Size j = (i << 1) + 1; j < __nb_elements; i = j, j = (j << 1) + 1) {
626  // let j be the max child
627  if ((j + 1 < __nb_elements) && __cmp(__heap[j + 1].first, __heap[j].first))
628  ++j;
629 
630  // if "val" is lower than heap[j], "val" must be stored at index i
631  if (__cmp(new_priority, __heap[j].first)) break;
632 
633  // else pull up the jth node
634  __heap[i] = std::move(__heap[j]);
635  std::vector< Size >& vect_index = __indices[*(__heap[i].second)];
636  for (auto& idx : vect_index) {
637  if (idx == j) {
638  idx = i;
639  break;
640  }
641  }
642  }
643 
644  // update the index of val
645  __heap[i].first = std::move(new_priority);
646  __heap[i].second = val;
647  std::vector< Size >& vect_index = __indices[*(__heap[i].second)];
648  for (auto& idx : vect_index) {
649  if (idx == index) {
650  idx = i;
651  break;
652  }
653  }
654 
655  return i;
656  }
657 
658  // modifies the priority of each instance of a given element
659  template < typename Val, typename Priority, typename Cmp, typename Alloc >
661  const Val& elt, const Priority& new_priority) {
662  std::vector< Size >& vect_index = __indices[elt];
663 
664  for (auto index : vect_index) {
665  setPriorityByPos(index, new_priority);
666  }
667  }
668 
669  // modifies the priority of each instance of a given element
670  template < typename Val, typename Priority, typename Cmp, typename Alloc >
672  const Val& elt) const {
673  return __heap[__indices[elt][0]].first;
674  }
675 
676  // A \c << operator for priority queues
677  template < typename Val, typename Priority, typename Cmp, typename Alloc >
678  INLINE std::ostream&
679  operator<<(std::ostream& stream,
681  stream << queue.toString();
682  return stream;
683  }
684 
685 } /* namespace gum */
Copyright 2005-2019 Pierre-Henri WUILLEMIN et Christophe GONZALES (LIP6) {prenom.nom}_at_lip6.fr.
INLINE std::ostream & operator<<(std::ostream &stream, const MultiPriorityQueue< Val, Priority, Cmp, Alloc > &queue)
std::vector< std::pair< Priority, const Val *>, HeapAlloc > __heap
An array storing all the elements of the heap as well as their score.
friend class MultiPriorityQueue
Making all MultiPriorityQueue friend with themselves.
Size __nb_elements
The number of elements in the heap.
std::string toString() const
Displays the content of the queue.
Cmp __cmp
Comparison function.
void clear()
Removes all the elements from the queue.
void erase(const Val &val)
Removes a given element from the priority queue (but does not return it).
STL namespace.
Copyright 2005-2019 Pierre-Henri WUILLEMIN et Christophe GONZALES (LIP6) {prenom.nom}_at_lip6.fr.
Definition: agrum.h:25
The class for generic Hash Tables.
Definition: hashTable.h:679
Size insert(const Val &val, const Priority &priority)
Inserts a new (a copy) element in the priority queue.
void resize(Size new_size)
Changes the size of the internal structure storing the priority queue.
std::size_t Size
In aGrUM, hashed values are unsigned long int.
Definition: types.h:48
A MultiPriorityQueue is a heap in which each element has a mutable priority and duplicates are allowe...
HashTable< Val, std::vector< Size >, IndexAlloc > __indices
A hashtable for quickly finding the elements by their value.
#define GUM_ERROR(type, msg)
Definition: exceptions.h:55