Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

HotQueue.h
Go to the documentation of this file.
1 
32 #pragma once
33 
34 #include <cmath>
35 #include <functional>
36 #include <limits>
37 #include <utility>
38 #include <vector>
39 
40 namespace ogdf {
41 
42 
44 template<typename V, typename P>
45 struct HotQueueNode {
46  V value;
48 
51 
52  HotQueueNode() : prev(nullptr), next(nullptr) { }
53 
54  HotQueueNode(const V& val, const P& pr)
55  : value(val), priority(pr), prev(nullptr), next(nullptr) { }
56 };
57 
59 
67 template<typename V, typename P, typename HeapHandle>
69 private:
70  enum class Type { heap, bucket } type;
71 
72  union {
74  HeapHandle heapHandle;
76  std::pair<std::size_t, HotQueueNode<V, P>*> bucketHandle;
77  };
78 
80  HotQueueHandle(HeapHandle handle) : type(Type::heap), heapHandle(handle) { }
81 
83  HotQueueHandle(std::size_t index, HotQueueNode<V, P>* queueNode)
84  : type(Type::bucket), bucketHandle(index, queueNode) { }
85 
86 public:
87  HotQueueHandle(const HotQueueHandle& other) { operator=(other); }
88 
90  type = other.type;
91  switch (type) {
92  case Type::heap:
93  heapHandle = other.heapHandle;
94  break;
95  case Type::bucket:
96  bucketHandle = other.bucketHandle;
97  break;
98  }
99 
100  return *this;
101  }
102 
103  template<typename V1, typename P1, template<typename T, typename C> class H1>
104  friend class HotQueue;
105 };
106 
108 
119 template<typename V, typename P, template<typename T, typename C> class H>
120 class HotQueue {
121 private:
122  struct HeapComparator;
123  using HeapHandle = typename H<std::pair<V, P>, HeapComparator>::Handle;
124 
125  std::size_t m_size;
126 
127  H<std::pair<V, P>, HeapComparator> m_heap;
128  std::size_t m_heapSize;
129 
130  std::vector<HotQueueNode<V, P>*> m_buckets;
131 
132 public:
134 
136 
140  HotQueue(const P& change, std::size_t levels);
141 
143  ~HotQueue();
144 
146  const V& top() const;
147 
149 
154  Handle push(const V& value, const P& priority);
155 
157 
160  void pop();
161 
163 
171  void decrease(Handle& handle, const P& priority);
172 
174  std::size_t size() const { return m_size; }
175 
177  bool empty() const { return size() == 0; }
178 
179 private:
181  struct HeapComparator {
182  bool operator()(const std::pair<V, P>& a, const std::pair<V, P>& b) const {
183  return std::get<1>(a) < std::get<1>(b);
184  }
185  };
186 
187  std::size_t m_heapedBucket;
188  std::size_t m_lastBucket;
189 
190  const P m_bucketSpan;
191 
193  std::size_t bucketIndex(const P& priority) {
194  return (std::size_t)std::round(priority / m_bucketSpan);
195  }
196 
198  HotQueueNode<V, P>*& bucketAt(std::size_t index) { return m_buckets[index % m_buckets.size()]; }
199 
200  static constexpr std::size_t NONE = std::numeric_limits<size_t>::max();
201 };
202 
203 template<typename V, typename P, template<typename T, typename C> class H>
204 HotQueue<V, P, H>::HotQueue(const P& change, std::size_t levels)
205  : m_size(0)
206  , m_heapSize(0)
207  , m_buckets(levels, nullptr)
208  , m_heapedBucket(NONE)
209  , m_lastBucket(0)
210  , m_bucketSpan((int)std::round(change / (levels - 1))) { }
211 
212 template<typename V, typename P, template<typename T, typename C> class H>
214  if (empty()) {
215  return;
216  }
217  for (auto& bucket : m_buckets) {
218  if (bucket != nullptr) {
219  for (HotQueueNode<V, P>* it = bucket; it != nullptr;) {
220  HotQueueNode<V, P>* next = it->next;
221  delete it;
222  it = next;
223  }
224  }
225  }
226 }
227 
228 template<typename V, typename P, template<typename T, typename C> class H>
229 inline const V& HotQueue<V, P, H>::top() const {
230  return std::get<0>(m_heap.top());
231 }
232 
233 template<typename V, typename P, template<typename T, typename C> class H>
234 typename HotQueue<V, P, H>::Handle HotQueue<V, P, H>::push(const V& value, const P& priority) {
235  m_size++;
236 
237  std::size_t ind = bucketIndex(priority);
238 
239  if (m_heapedBucket == NONE) {
240  m_heapedBucket = ind;
241  }
242 
243  if (ind == m_heapedBucket) {
244  m_heapSize++;
245  HeapHandle handle = m_heap.push(std::make_pair(value, priority));
246  return Handle(handle);
247  } else {
248  HotQueueNode<V, P>* queueNode = new HotQueueNode<V, P>(value, priority);
249 
250  if (bucketAt(ind) != nullptr) {
251  bucketAt(ind)->prev = queueNode;
252  }
253  queueNode->next = bucketAt(ind);
254  bucketAt(ind) = queueNode;
255 
256  m_lastBucket = std::max(m_lastBucket, ind);
257  return Handle(ind, queueNode);
258  }
259 }
260 
261 template<typename V, typename P, template<typename T, typename C> class H>
263  m_size--;
264 
265  m_heap.pop();
266  m_heapSize--;
267 
268  /*
269  * If the heap became empty and there is non-empty bucket afterwards
270  * we need to heapify first non-empty bucket. If the heap became empty
271  * but there is no non-empty bucket afterwards it may be the case that
272  * element will be inserted into the current heap (therefore, do nothing).
273  */
274  if (!(m_heapSize == 0 && m_heapedBucket != m_lastBucket)) {
275  return;
276  }
277 
278  // Find first non-empty bucket.
279  do {
280  m_heapedBucket++;
281  } while (bucketAt(m_heapedBucket) == nullptr);
282 
283  // Move bucket contents into a heap.
284  for (HotQueueNode<V, P>* it = bucketAt(m_heapedBucket); it != nullptr;) {
285  m_heapSize++;
286  m_heap.push(std::make_pair(it->value, it->priority));
287 
288  HotQueueNode<V, P>* next = it->next;
289  delete it;
290  it = next;
291  }
292  bucketAt(m_heapedBucket) = nullptr;
293 }
294 
295 template<typename V, typename P, template<typename T, typename C> class H>
296 void HotQueue<V, P, H>::decrease(typename HotQueue<V, P, H>::Handle& handle, const P& priority) {
297  switch (handle.type) {
298  case Handle::Type::heap: {
299  // Simple case, just use native heap decrease key.
300  const HeapHandle& elem = handle.heapHandle;
301  m_heap.decrease(elem, std::make_pair(std::get<0>(m_heap.value(elem)), priority));
302  break;
303  }
304  case Handle::Type::bucket:
305  // Remove element from bucket (as with ordinary linked-list)...
306  HotQueueNode<V, P>* queueNode = std::get<1>(handle.bucketHandle);
307  if (queueNode->next != nullptr) {
308  queueNode->next->prev = queueNode->prev;
309  }
310  if (queueNode->prev != nullptr) {
311  queueNode->prev->next = queueNode->next;
312  } else {
313  m_buckets[std::get<0>(handle.bucketHandle)] = queueNode->next;
314  }
315 
316  // ... and push it again with new priority, releasing the memory.
317  m_size--;
318  handle = push(queueNode->value, priority);
319  delete queueNode;
320  break;
321  }
322 }
323 
324 }
ogdf
The namespace for all OGDF objects.
Definition: AugmentationModule.h:36
ogdf::HotQueue::HeapHandle
typename H< std::pair< V, P >, HeapComparator >::Handle HeapHandle
Definition: HotQueue.h:123
ogdf::HotQueueHandle::type
enum ogdf::HotQueueHandle::Type type
Union tag.
ogdf::HotQueue::HeapComparator
Comparator used by underlying heap.
Definition: HotQueue.h:181
ogdf::HotQueue::bucketAt
HotQueueNode< V, P > *& bucketAt(std::size_t index)
Provides access to bucket at given index.
Definition: HotQueue.h:198
ogdf::HotQueueNode
Heap-on-Top bucket element.
Definition: HotQueue.h:45
ogdf::HotQueue::m_lastBucket
std::size_t m_lastBucket
Index of highest, non-empty bucket.
Definition: HotQueue.h:188
ogdf::HotQueue::size
std::size_t size() const
Number of elements contained within the heap.
Definition: HotQueue.h:174
ogdf::HotQueue::push
Handle push(const V &value, const P &priority)
Inserts a new node with given value and priority into a heap.
Definition: HotQueue.h:234
ogdf::HotQueue::~HotQueue
~HotQueue()
Releases all buckets on destruction.
Definition: HotQueue.h:213
ogdf::HotQueue::m_bucketSpan
const P m_bucketSpan
Length of the interval covered by each bucket.
Definition: HotQueue.h:190
ogdf::HotQueueHandle
Heap-on-Top handle to inserted items.
Definition: HotQueue.h:68
ogdf::HotQueue::empty
bool empty() const
Checks whether the heap is empty.
Definition: HotQueue.h:177
ogdf::HotQueueHandle::bucketHandle
std::pair< std::size_t, HotQueueNode< V, P > * > bucketHandle
Handle to bucket element (bucket index and list iterator).
Definition: HotQueue.h:76
ogdf::HotQueueHandle::HotQueueHandle
HotQueueHandle(const HotQueueHandle &other)
Definition: HotQueue.h:87
ogdf::HotQueue::m_heap
H< std::pair< V, P >, HeapComparator > m_heap
Underlying heap structure.
Definition: HotQueue.h:127
ogdf::HotQueueHandle::operator=
HotQueueHandle & operator=(const HotQueueHandle &other)
Definition: HotQueue.h:89
ogdf::HotQueueHandle::Type::bucket
@ bucket
ogdf::HotQueue::HotQueue
HotQueue(const P &change, std::size_t levels)
Creates empty Heap-on-Top queue.
Definition: HotQueue.h:204
ogdf::HotQueue::bucketIndex
std::size_t bucketIndex(const P &priority)
Computes bucket index of given priority.
Definition: HotQueue.h:193
ogdf::HotQueueNode::next
HotQueueNode< V, P > * next
Definition: HotQueue.h:50
ogdf::HotQueue::top
const V & top() const
Returns reference to the top element in the heap.
Definition: HotQueue.h:229
ogdf::HotQueue::m_heapSize
std::size_t m_heapSize
Size of underlying heap.
Definition: HotQueue.h:128
ogdf::HotQueueHandle::heapHandle
HeapHandle heapHandle
Handle to underlying heap.
Definition: HotQueue.h:74
ogdf::HotQueueNode::HotQueueNode
HotQueueNode()
Definition: HotQueue.h:52
ogdf::HotQueueHandle::Type::heap
@ heap
ogdf::HotQueueNode::priority
P priority
Definition: HotQueue.h:47
std
Definition: GML.h:110
ogdf::HotQueue::Handle
HotQueueHandle< V, P, HeapHandle > Handle
Definition: HotQueue.h:133
ogdf::HotQueue::m_buckets
std::vector< HotQueueNode< V, P > * > m_buckets
Array of buckets.
Definition: HotQueue.h:130
ogdf::HotQueue::decrease
void decrease(Handle &handle, const P &priority)
Decreases value of the given handle to priority.
Definition: HotQueue.h:296
ogdf::HotQueueNode::prev
HotQueueNode< V, P > * prev
Definition: HotQueue.h:49
ogdf::HotQueueHandle::HotQueueHandle
HotQueueHandle(std::size_t index, HotQueueNode< V, P > *queueNode)
Creates bucket-type handle.
Definition: HotQueue.h:83
ogdf::HotQueueNode::HotQueueNode
HotQueueNode(const V &val, const P &pr)
Definition: HotQueue.h:54
ogdf::HotQueueNode::value
V value
Definition: HotQueue.h:46
ogdf::HotQueue
Heap-on-Top queue implementation.
Definition: HotQueue.h:120
ogdf::HotQueueHandle::HotQueueHandle
HotQueueHandle(HeapHandle handle)
Creates heap-type handle.
Definition: HotQueue.h:80
ogdf::HotQueue::m_size
std::size_t m_size
Number of total elements in the heap.
Definition: HotQueue.h:125
ogdf::HotQueue::NONE
static constexpr std::size_t NONE
Definition: HotQueue.h:200
ogdf::HotQueueHandle::Type
Type
Definition: HotQueue.h:70
ogdf::HotQueue::pop
void pop()
Removes the top element from the heap.
Definition: HotQueue.h:262
ogdf::HotQueue::m_heapedBucket
std::size_t m_heapedBucket
Index of currently heaped bucket.
Definition: HotQueue.h:187
ogdf::HotQueue::HeapComparator::operator()
bool operator()(const std::pair< V, P > &a, const std::pair< V, P > &b) const
Definition: HotQueue.h:182