11#include "clustering/math/detail/heap_ops.h"
37 void push(Key key, Val val) {
38 m_heap.emplace_back(std::move(key), std::move(val));
39 math::detail::siftUp(m_heap, m_heap.size() - 1, minOnKey);
49 [[nodiscard]]
const std::pair<Key, Val> &
top() const noexcept {
50 assert(!m_heap.empty() &&
"BinaryHeap::top on empty heap");
51 return m_heap.front();
61 assert(!m_heap.empty() &&
"BinaryHeap::pop on empty heap");
62 const std::size_t last = m_heap.size() - 1;
64 m_heap[0] = std::move(m_heap[last]);
67 if (!m_heap.empty()) {
68 math::detail::siftDown(m_heap, 0, minOnKey);
77 [[nodiscard]] std::size_t
size() const noexcept {
return m_heap.size(); }
84 [[nodiscard]]
bool empty() const noexcept {
return m_heap.empty(); }
88 static bool minOnKey(
const std::pair<Key, Val> &a,
const std::pair<Key, Val> &b)
noexcept {
89 return a.first < b.first;
92 std::vector<std::pair<Key, Val>> m_heap;
109template <
class Key,
class Val,
class Idx = std::u
int32_t>
class IndexedHeap {
111 static_assert(std::is_unsigned_v<Idx>,
"IndexedHeap Idx must be an unsigned integer type");
114 static constexpr std::size_t
kNotInHeap = std::numeric_limits<std::size_t>::max();
149 void push(Idx handle, Key key, Val val) {
150 assert(
static_cast<std::size_t
>(handle) < m_posMap.size() &&
151 "IndexedHeap::push handle out of range");
152 assert(m_posMap[handle] ==
kNotInHeap &&
"IndexedHeap::push handle already in heap");
153 const std::size_t pos = m_heap.size();
154 m_heap.push_back(
Entry{handle, std::move(key), std::move(val)});
155 m_posMap[handle] = pos;
165 [[nodiscard]]
bool contains(Idx handle)
const noexcept {
166 assert(
static_cast<std::size_t
>(handle) < m_posMap.size() &&
167 "IndexedHeap::contains handle out of range");
182 assert(
static_cast<std::size_t
>(handle) < m_posMap.size() &&
183 "IndexedHeap::decreaseKey handle out of range");
184 const std::size_t pos = m_posMap[handle];
185 assert(pos !=
kNotInHeap &&
"IndexedHeap::decreaseKey handle not in heap");
186 assert(!(m_heap[pos].key < newKey) &&
"IndexedHeap::decreaseKey newKey > current key");
187 m_heap[pos].key = std::move(newKey);
199 assert(!m_heap.empty() &&
"IndexedHeap::top on empty heap");
200 return m_heap.front();
211 assert(!m_heap.empty() &&
"IndexedHeap::pop on empty heap");
212 Entry out = std::move(m_heap.front());
214 const std::size_t last = m_heap.size() - 1;
216 m_heap.front() = std::move(m_heap[last]);
217 m_posMap[m_heap.front().handle] = 0;
220 if (!m_heap.empty()) {
231 [[nodiscard]] std::size_t
size() const noexcept {
return m_heap.size(); }
238 [[nodiscard]]
bool empty() const noexcept {
return m_heap.empty(); }
245 [[nodiscard]] std::size_t
capacity() const noexcept {
return m_posMap.size(); }
248 std::vector<Entry> m_heap;
249 std::vector<std::size_t> m_posMap;
251 void swapEntries(std::size_t i, std::size_t j)
noexcept {
252 std::swap(m_heap[i], m_heap[j]);
253 m_posMap[m_heap[i].handle] = i;
254 m_posMap[m_heap[j].handle] = j;
257 void siftUp(std::size_t pos)
noexcept {
259 const std::size_t parent = (pos - 1) / 2;
260 if (m_heap[pos].key < m_heap[parent].key) {
261 swapEntries(pos, parent);
269 void siftDown(std::size_t pos)
noexcept {
270 const std::size_t n = m_heap.size();
272 const std::size_t left = (2 * pos) + 1;
273 const std::size_t right = left + 1;
274 std::size_t smallest = pos;
275 if (left < n && m_heap[left].key < m_heap[smallest].key) {
278 if (right < n && m_heap[right].key < m_heap[smallest].key) {
281 if (smallest == pos) {
284 swapEntries(pos, smallest);
const std::pair< Key, Val > & top() const noexcept
Smallest-key entry currently in the heap.
std::size_t size() const noexcept
Current number of entries.
void pop() noexcept
Remove the smallest-key entry.
bool empty() const noexcept
Whether the heap holds zero entries.
void push(Key key, Val val)
Insert a new (key, val) entry.
bool contains(Idx handle) const noexcept
Whether handle is currently present in the heap.
std::size_t capacity() const noexcept
Maximum handle + 1 (the capacity passed at construction).
void push(Idx handle, Key key, Val val)
Insert an entry for handle.
static constexpr std::size_t kNotInHeap
Sentinel for "handle not currently in the heap". Equal to size_t's max.
void decreaseKey(Idx handle, Key newKey) noexcept
Lower the key of handle's entry to newKey.
IndexedHeap(std::size_t capacity)
Construct an empty heap capable of handles in [0, capacity).
std::size_t size() const noexcept
Current number of entries.
bool empty() const noexcept
Whether the heap holds zero entries.
const Entry & top() const noexcept
Smallest-key entry currently in the heap.
Entry pop() noexcept
Remove and return the smallest-key entry.
Idx handle
External identity supplied by the caller at push time.
Val val
Payload associated with handle.
Key key
Ordering key; the heap root carries the smallest key.