Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

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