Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

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 
42 namespace ogdf {
43 
44 
46 template<typename V, typename P>
47 struct HotQueueNode {
48  V value;
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 
69 template<typename V, typename P, typename HeapHandle>
71 private:
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 
88 public:
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:
98  bucketHandle = other.bucketHandle;
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 
121 template<typename V, typename P, template<typename T, typename C> class H>
122 class HotQueue {
123 private:
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 
135 public:
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 
182 private:
184  struct HeapComparator {
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 
206 template<typename V, typename P, template<typename T, typename C> class H>
207 HotQueue<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 
215 template<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 
231 template<typename V, typename P, template<typename T, typename C> class H>
232 inline const V& HotQueue<V, P, H>::top() const {
233  return std::get<0>(m_heap.top());
234 }
235 
236 template<typename V, typename P, template<typename T, typename C> class H>
237 typename 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 
264 template<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 
298 template<typename V, typename P, template<typename T, typename C> class H>
299 void 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 }
ogdf
The namespace for all OGDF objects.
Definition: multilevelmixer.cpp:39
ogdf::HotQueue::HeapHandle
typename H< std::pair< V, P >, HeapComparator >::Handle HeapHandle
Definition: HotQueue.h:126
ogdf::HotQueueHandle::type
enum ogdf::HotQueueHandle::Type type
Union tag.
ogdf::HotQueue::HeapComparator
Comparator used by underlying heap.
Definition: HotQueue.h:184
ogdf::HotQueue::bucketAt
HotQueueNode< V, P > *& bucketAt(std::size_t index)
Provides access to bucket at given index.
Definition: HotQueue.h:201
ogdf::HotQueueNode
Heap-on-Top bucket element.
Definition: HotQueue.h:47
ogdf::HotQueue::m_lastBucket
std::size_t m_lastBucket
Index of highest, non-empty bucket.
Definition: HotQueue.h:191
ogdf::HotQueue::size
std::size_t size() const
Number of elements contained within the heap.
Definition: HotQueue.h:177
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:237
ogdf::HotQueue::~HotQueue
~HotQueue()
Releases all buckets on destruction.
Definition: HotQueue.h:216
ogdf::HotQueue::m_bucketSpan
const P m_bucketSpan
Length of the interval covered by each bucket.
Definition: HotQueue.h:193
ogdf::HotQueueHandle
Heap-on-Top handle to inserted items.
Definition: HotQueue.h:70
ogdf::HotQueue::empty
bool empty() const
Checks whether the heap is empty.
Definition: HotQueue.h:180
ogdf::HotQueueHandle::bucketHandle
std::pair< std::size_t, HotQueueNode< V, P > * > bucketHandle
Handle to bucket element (bucket index and list iterator).
Definition: HotQueue.h:78
ogdf::HotQueueHandle::HotQueueHandle
HotQueueHandle(const HotQueueHandle &other)
Definition: HotQueue.h:89
ogdf::HotQueue::m_heap
H< std::pair< V, P >, HeapComparator > m_heap
Underlying heap structure.
Definition: HotQueue.h:130
ogdf::HotQueueHandle::operator=
HotQueueHandle & operator=(const HotQueueHandle &other)
Definition: HotQueue.h:91
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:207
ogdf::HotQueue::bucketIndex
std::size_t bucketIndex(const P &priority)
Computes bucket index of given priority.
Definition: HotQueue.h:196
ogdf::HotQueueNode::next
HotQueueNode< V, P > * next
Definition: HotQueue.h:52
ogdf::HotQueue::top
const V & top() const
Returns reference to the top element in the heap.
Definition: HotQueue.h:232
ogdf::HotQueue::m_heapSize
std::size_t m_heapSize
Size of underlying heap.
Definition: HotQueue.h:131
ogdf::HotQueueHandle::heapHandle
HeapHandle heapHandle
Handle to underlying heap.
Definition: HotQueue.h:76
ogdf::HotQueueNode::HotQueueNode
HotQueueNode()
Definition: HotQueue.h:54
ogdf::HotQueueHandle::Type::heap
@ heap
ogdf::HotQueueNode::priority
P priority
Definition: HotQueue.h:49
std
Definition: GML.h:111
ogdf::HotQueue::Handle
HotQueueHandle< V, P, HeapHandle > Handle
Definition: HotQueue.h:136
ogdf::HotQueue::m_buckets
std::vector< HotQueueNode< V, P > * > m_buckets
Array of buckets.
Definition: HotQueue.h:133
ogdf::HotQueue::decrease
void decrease(Handle &handle, const P &priority)
Decreases value of the given handle to priority.
Definition: HotQueue.h:299
ogdf::HotQueueNode::prev
HotQueueNode< V, P > * prev
Definition: HotQueue.h:51
ogdf::HotQueueHandle::HotQueueHandle
HotQueueHandle(std::size_t index, HotQueueNode< V, P > *queueNode)
Creates bucket-type handle.
Definition: HotQueue.h:85
ogdf::HotQueueNode::HotQueueNode
HotQueueNode(const V &val, const P &pr)
Definition: HotQueue.h:56
ogdf::HotQueueNode::value
V value
Definition: HotQueue.h:48
ogdf::HotQueue
Heap-on-Top queue implementation.
Definition: HotQueue.h:122
ogdf::HotQueueHandle::HotQueueHandle
HotQueueHandle(HeapHandle handle)
Creates heap-type handle.
Definition: HotQueue.h:82
ogdf::HotQueue::m_size
std::size_t m_size
Number of total elements in the heap.
Definition: HotQueue.h:128
ogdf::HotQueue::NONE
static constexpr std::size_t NONE
Definition: HotQueue.h:203
ogdf::HotQueueHandle::Type
Type
Definition: HotQueue.h:72
ogdf::HotQueue::pop
void pop()
Removes the top element from the heap.
Definition: HotQueue.h:265
ogdf::HotQueue::m_heapedBucket
std::size_t m_heapedBucket
Index of currently heaped bucket.
Definition: HotQueue.h:190
ogdf::HotQueue::HeapComparator::operator()
bool operator()(const std::pair< V, P > &a, const std::pair< V, P > &b) const
Definition: HotQueue.h:185