SolidUtils
FixedPriorityQueue.hpp
Go to the documentation of this file.
1 
31 #ifndef SOLIDUTILS_INCLUDE_FIXEDPRIORITYQUEUE_HPP
32 #define SOLIDUTILS_INCLUDE_FIXEDPRIORITYQUEUE_HPP
33 
34 #include "Array.hpp"
35 
36 namespace sl
37 {
38 
39 
48 template<typename K, typename V>
50 {
51  public:
52  static constexpr size_t const NULL_INDEX = static_cast<size_t>(-1);
53 
54  class ValueSet
55  {
56  public:
57  class Iterator
58  {
59  public:
67  size_t const index,
68  FixedPriorityQueue<K,V> const * const q) :
69  m_index(index),
70  m_q(q)
71  {
72  // do nothing
73  }
74 
80  inline V operator*() const noexcept
81  {
82  size_t const pos = m_q->m_index[m_index];
83  return m_q->m_data[pos].value;
84  }
85 
91  inline Iterator & operator++()
92  {
93  do {
94  ++m_index;
95  } while (m_index < m_q->m_index.size() && \
96  m_q->m_index[m_index] == NULL_INDEX);
97 
98  return *this;
99  }
100 
108  inline bool operator==(
109  Iterator const & other) const
110  {
111  return m_index == other.m_index;
112  }
113 
121  inline bool operator!=(
122  Iterator const & other) const
123  {
124  return !(*this == other);
125  }
126 
127  private:
128  size_t m_index;
129  FixedPriorityQueue<K,V> const * m_q;
130  };
131 
138  FixedPriorityQueue<K,V> const * const q) :
139  m_q(q)
140  {
141  // do nothing
142  }
143 
149  inline Iterator begin() const noexcept
150  {
151  // find first valid index
152  size_t index = 0;
153  while (index < m_q->m_index.size() && \
154  m_q->m_index[index] == NULL_INDEX) {
155  ++index;
156  }
157 
158  return Iterator(index, m_q);
159  }
160 
166  inline Iterator end() const noexcept
167  {
168  return Iterator(m_q->m_index.size(), m_q);
169  }
170 
171  private:
172  FixedPriorityQueue<K,V> const * m_q;
173  };
174 
181  V const max) :
182  m_data(max),
183  m_index(max, NULL_INDEX),
184  m_size(0)
185  {
186  // do nothing
187  }
188 
189 
195  void remove(
196  V const value) noexcept
197  {
198  ASSERT_LESS(static_cast<size_t>(value), m_index.size());
199  ASSERT_NOTEQUAL(m_index[value], NULL_INDEX);
200 
201  // remove item from heap and sort up
202  size_t const index = m_index[value];
203  fill(index);
204  }
205 
206 
213  void add(
214  K const key,
215  V const value) noexcept
216  {
217  ASSERT_LESS(static_cast<size_t>(value), m_index.size());
218  ASSERT_EQUAL(m_index[value], NULL_INDEX);
219 
220  size_t const index = m_size++;
221  m_index[value] = index;
222  m_data[index].key = key;
223  m_data[index].value = value;
224 
225  siftUp(index);
226  }
227 
228 
235  void update(
236  K const key,
237  V const value) noexcept
238  {
239  ASSERT_LESS(static_cast<size_t>(value), m_index.size());
240  ASSERT_NOTEQUAL(m_index[value], NULL_INDEX);
241 
242  size_t const index = m_index[value];
243  m_data[index].key = key;
244 
245  // update position
246  if (index > 0 && key > m_data[parentIndex(index)].key) {
247  siftUp(index);
248  } else {
249  siftDown(index);
250  }
251  }
252 
253 
261  K const delta,
262  V const value) noexcept
263  {
264  ASSERT_LESS(static_cast<size_t>(value), m_index.size());
265  ASSERT_NOTEQUAL(m_index[value], NULL_INDEX);
266 
267  size_t const index = m_index[value];
268  K const key = m_data[index].key + delta;
269 
270  update(key, value);
271  }
272 
280  bool contains(
281  V const value) const noexcept
282  {
283  ASSERT_LESS(static_cast<size_t>(value), m_index.size());
284 
285  return m_index[value] != NULL_INDEX;
286  }
287 
288 
296  K get(
297  V const value) const noexcept
298  {
299  ASSERT_LESS(static_cast<size_t>(value), m_index.size());
300  ASSERT_NOTEQUAL(m_index[value], NULL_INDEX);
301 
302  return m_data[m_index[value]].key;
303  }
304 
305 
311  V pop() noexcept
312  {
313  ASSERT_GREATER(m_size, 0);
314 
315  V const value = m_data[0].value;
316  fill(0);
317 
318  return value;
319  }
320 
321 
327  V const & peek() const noexcept
328  {
329  return m_data[0].value;
330  }
331 
332 
338  K const & max() const noexcept
339  {
340  return m_data[0].key;
341  }
342 
343 
349  size_t size() const noexcept
350  {
351  return m_size;
352  }
353 
354 
358  void clear() noexcept
359  {
360  for (size_t i = 0; i < m_size; ++i) {
361  m_index[m_data[i].value] = NULL_INDEX;
362  }
363  m_size = 0;
364  }
365 
366 
373  ValueSet remaining() const noexcept
374  {
375  return ValueSet(this);
376  }
377 
378 
379  private:
380  struct kv_pair_struct
381  {
382  K key;
383  V value;
384  };
385 
386  Array<kv_pair_struct> m_data;
387  Array<size_t> m_index;
388  size_t m_size;
389 
390 
398  size_t parentIndex(
399  size_t const index) const noexcept
400  {
401  return index / 2;
402  }
403 
404 
412  size_t leftChildIndex(
413  size_t const index) const noexcept
414  {
415  return (index * 2)+1;
416  }
417 
418 
426  size_t rightChildIndex(
427  size_t const index) const noexcept
428  {
429  return leftChildIndex(index) + 1;
430  }
431 
432 
439  void swap(
440  size_t const indexA,
441  size_t const indexB) noexcept
442  {
443  V const valueA = m_data[indexA].value;
444  V const valueB = m_data[indexB].value;
445 
446  std::swap(m_index[valueA], m_index[valueB]);
447  std::swap(m_data[indexA], m_data[indexB]);
448  }
449 
450 
456  void fill(
457  size_t const index) noexcept
458  {
459  ASSERT_LESS(index, m_size);
460 
461  --m_size;
462  V const deletedValue = m_data[index].value;
463 
464  if (m_size > 0) {
465  // what we'll do is move the bottom node to this position
466  m_data[index] = m_data[m_size];
467 
468  V const value = m_data[index].value;
469  m_index[value] = index;
470 
471  siftDown(index);
472  }
473 
474  m_index[deletedValue] = NULL_INDEX;
475  }
476 
477 
483  void siftUp(
484  size_t index) noexcept
485  {
486  while (index > 0) {
487  size_t const parent = parentIndex(index);
488  if (m_data[parent].key >= m_data[index].key) {
489  // reached a valid state
490  break;
491  }
492  swap(index, parent);
493  index = parent;
494  }
495  }
496 
497 
503  void siftDown(
504  size_t index) noexcept
505  {
506  K const key = m_data[index].key;
507  while (true) {
508  size_t const leftIndex = leftChildIndex(index);
509  size_t const rightIndex = rightChildIndex(index);
510  if (rightIndex < m_size && key < m_data[rightIndex].key) {
511  if (m_data[rightIndex].key >= m_data[leftIndex].key) {
512  swap(index, rightIndex);
513  index = rightIndex;
514  } else {
515  swap(index, leftIndex);
516  index = leftIndex;
517  }
518  } else if (leftIndex < m_size && key < m_data[leftIndex].key) {
519  swap(index, leftIndex);
520  index = leftIndex;
521  } else {
522  // life is good -- exit
523  break;
524  }
525  }
526  }
527 };
528 
529 
530 }
531 
532 #endif
Iterator(size_t const index, FixedPriorityQueue< K, V > const *const q)
Create a new forward iterator.
Definition: FixedPriorityQueue.hpp:66
bool contains(V const value) const noexcept
Check if a value in present in the priority queue.
Definition: FixedPriorityQueue.hpp:280
bool operator==(Iterator const &other) const
Check if this iterator is the same as another.
Definition: FixedPriorityQueue.hpp:108
size_t size() const noexcept
Get the number of elements in the queue.
Definition: FixedPriorityQueue.hpp:349
Definition: FixedPriorityQueue.hpp:57
Definition: Alloc.hpp:40
Iterator begin() const noexcept
Get the forward iterator to the start of the set.
Definition: FixedPriorityQueue.hpp:149
void clear() noexcept
Clear entries from the priority queue.
Definition: FixedPriorityQueue.hpp:358
ValueSet(FixedPriorityQueue< K, V > const *const q)
Create a new value set.
Definition: FixedPriorityQueue.hpp:137
V pop() noexcept
Pop the top value from the queue.
Definition: FixedPriorityQueue.hpp:311
void updateByDelta(K const delta, V const value) noexcept
Update the key associated with a given value by modifying the key.
Definition: FixedPriorityQueue.hpp:260
Definition: FixedPriorityQueue.hpp:54
K const & max() const noexcept
Get get the top of the priority queue&#39;s value.
Definition: FixedPriorityQueue.hpp:338
ValueSet remaining() const noexcept
Get the set of remaining items in the priority. The order of the values is arbitrary.
Definition: FixedPriorityQueue.hpp:373
bool operator!=(Iterator const &other) const
Check if this iterator is different from another iterator.
Definition: FixedPriorityQueue.hpp:121
void add(K const key, V const value) noexcept
Add an value to the queue.
Definition: FixedPriorityQueue.hpp:213
V const & peek() const noexcept
Get get the top of the priority queue&#39;s value.
Definition: FixedPriorityQueue.hpp:327
Iterator & operator++()
Move the iterator forward.
Definition: FixedPriorityQueue.hpp:91
The FixedPriorityQueue class provides a priority queue implementation with the standard O(log n) inse...
Definition: FixedPriorityQueue.hpp:49
A mutable array structure for storing self-allocated memory.
V operator*() const noexcept
Get the value of the iterator.
Definition: FixedPriorityQueue.hpp:80
FixedPriorityQueue(V const max)
Create a new priority queue that can hold element 0 through max.
Definition: FixedPriorityQueue.hpp:180
Iterator end() const noexcept
Get the forward iterator to the end of the set.
Definition: FixedPriorityQueue.hpp:166
void update(K const key, V const value) noexcept
Update the key associated with a given value.
Definition: FixedPriorityQueue.hpp:235