Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_arrayHeap.H
Go to the documentation of this file.
1/*
2 Aleph_w
3
4 Data structures & Algorithms
5 version 2.0.0b
6 https://github.com/lrleon/Aleph-w
7
8 This file is part of Aleph-w library
9
10 Copyright (c) 2002-2026 Leandro Rabindranath Leon
11
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29*/
30
31
47#ifndef TPL_ARRAYHEAP_H
48#define TPL_ARRAYHEAP_H
49
50#include <algorithm>
51#include <cstddef>
52#include <stdexcept>
53#include <utility>
54
55#include <ahFunction.H>
56#include <ahUtils.H>
57#include <ahDefs.H>
58#include <ahAssert.H>
59#include <array_it.H>
60#include <htlist.H>
61#include <tpl_dynDlist.H>
62#include <ah-args-ctor.H>
63#include <ahDry.H>
64#include <ah-dry.H>
65#include <ah-errors.H>
66
67namespace Aleph
68{
83 template <typename T, class Compare>
84 inline
85 T &sift_up(T *ptr, const size_t l, const size_t r, Compare & cmp)
86 {
87 size_t i = r;
88 for (size_t p; i > l; i = p)
89 {
90 p = u_index(i); // parent index (p = i / 2)
91
92 // Prefetch grandparent for next iteration
93 if (const size_t gp = u_index(p); gp >= l)
94 __builtin_prefetch(&ptr[gp], 0, 1);
95
96 if (cmp(ptr[p], ptr[i])) [[likely]] // does the heap property hold?
97 return ptr[i]; // yes, the entire range is already a heap
98
99 std::swap(ptr[p], ptr[i]); // swap nodes and restore level p
100 }
101
102 return ptr[i];
103 }
104
118 template <typename T, class Compare>
119 inline
120 void sift_down(T *ptr, const size_t l, const size_t r, Compare & cmp)
121 {
122 size_t i = l;
123 while (true)
124 {
125 size_t c = l_index(i); // left child index (c = 2 * i)
126 if (c > r) [[unlikely]] // does it have a left child?
127 return; // no ==> stop
128
129 // Prefetch grandchildren for next iteration
130 if (const size_t gc = l_index(c); gc <= r)
131 __builtin_prefetch(&ptr[gc], 0, 1);
132
133 if (c + 1 <= r) // does it have a right child?
134 if (cmp(ptr[c + 1], ptr[c])) // yes ==> pick the smaller child
135 c++;
136
137 if (cmp(ptr[i], ptr[c])) [[likely]] // does the heap property hold?
138 return; // yes ==> stop
139
140 std::swap(ptr[c], ptr[i]);
141 i = c;
142 }
143 }
144
158 template <typename T, class Compare>
159 inline
160 void sift_down_up(T *ptr, const size_t l, const size_t i, const size_t r,
161 Compare & cmp)
162 {
163 sift_down<T, Compare>(ptr, i, r, cmp);
164 sift_up<T, Compare>(ptr, l, i, cmp);
165 }
166
182 template <typename T, class Compare = Aleph::less<T>>
183 inline
184 void heapsort(T *array, const size_t n, const Compare & cmp = Compare())
185 {
187
188 --array; // shift backwards so array[1] is the first element
189 for (size_t i = 2; i <= n; ++i)
191 for (size_t i = n; i > 1; --i)
192 {
193 std::swap(array[1], array[i]); // place the i-th item at the root
195 }
196 }
197
213 template <typename T, class Compare = Aleph::less<T>>
214 inline
215 void faster_heapsort(T *array, const size_t n, const Compare & cmp = Compare())
216 {
218
219 --array; // shift backwards so array[1] is the first element
220 for (size_t i = n / 2; i >= 1; --i)
221 sift_down(array, i, n, inv_cmp);
222 for (size_t i = n; i > 1; --i)
223 {
224 std::swap(array[1], array[i]); // place the i-th item at the root
225 sift_down(array, 1, i - 1, inv_cmp);
226 }
227 }
228
240 template <typename T, class Compare = Aleph::less<T>>
241 bool valid_heap(T *array, const size_t l, const size_t r,
242 const Compare & cmp = Compare())
243 {
244 size_t i;
245 for (i = l_index(l) /* i = 2*l */; i <= r; i++)
246 if (cmp(array[i], array[u_index(i)]))
247 break;
248 return i > r;
249 }
250
263 template <typename T, class Compare = Aleph::less<T>>
264 class ArrayHeap : public LocateFunctions<ArrayHeap<T, Compare>, T>,
265 public FunctionalMethods<ArrayHeap<T, Compare>, T>,
266 public GenericItems<ArrayHeap<T, Compare>, T>,
267 public EqualToMethod<ArrayHeap<T, Compare>>,
268 public StlAlephIterator<ArrayHeap<T, Compare>>
269 {
270 T *array = nullptr;
271 mutable size_t dim = 0;
272 size_t num_items = 0;
273
274 mutable bool array_allocated = false;
275
276 Compare cmp;
277
278 static size_t r_index(const size_t & i)
279 {
280 return (i << 1) + 1; // multiply i by 2 and add 1
281 }
282
283 public:
289 void allocate_storage(const size_t new_dim)
290 {
291 ah_invalid_argument_if(new_dim == 0) << "Heap capacity must be positive";
292
293 T *ptr = new T[new_dim + 1];
294 if (array_allocated)
295 delete [] array;
296
297 array = ptr;
298 dim = new_dim;
299 num_items = 0;
300 array_allocated = true;
301 }
302
307 void swap(ArrayHeap & h) noexcept
308 {
309 std::swap(array, h.array);
310 std::swap(dim, h.dim);
311 std::swap(num_items, h.num_items);
312 std::swap(array_allocated, h.array_allocated);
313 std::swap(cmp, h.cmp);
314 }
315
316 using Item_Type = T;
317
318 using Key_Type = T;
319
321
328 ArrayHeap(const size_t d = 1024, Compare cmp_fct = Compare())
330 {
332 }
333
343 ArrayHeap(T *ptr, const size_t & d, Compare cmp_fct = Compare())
344 : array(ptr), dim(d), cmp(cmp_fct)
345 {
346 ah_invalid_argument_if(ptr == nullptr or d == 0) << "ArrayHeap requires non-null buffer";
347 }
348
350 : array(nullptr), cmp(h.cmp)
351 {
352 allocate_storage(h.dim);
353 num_items = h.num_items;
354 for (size_t i = 1; i <= num_items; ++i)
355 array[i] = h.array[i];
356 }
357
359 : cmp(h.cmp)
360 {
361 swap(h);
362 }
363
365 {
366 if (this == &h)
367 return *this;
368
369 if (dim < h.dim)
370 allocate_storage(h.dim);
371
372 num_items = h.num_items;
373 for (size_t i = 1; i <= num_items; ++i)
374 array[i] = h.array[i];
375 cmp = h.cmp;
376
377 return *this;
378 }
379
381 noexcept
382 {
383 swap(h);
384 return *this;
385 }
386
388 virtual ~ArrayHeap()
389 {
390 if (array_allocated and array != nullptr)
391 delete [] array;
392 }
393
399 {
400 ah_underflow_error_if(num_items == 0) << "Heap is empty";
401
402 return array[1];
403 }
404
409 const T &top() const
410 {
411 ah_underflow_error_if(num_items == 0) << "Heap is empty";
412
413 return array[1];
414 }
415
423 T &insert_ne(const T & key)
424 {
425 array[++num_items] = key; // place the new element
426 return sift_up(array, 1, num_items, cmp);
427 }
428
436 T &insert_ne(T && key)
437 {
438 array[++num_items] = std::move(key); // place the new element
439 return sift_up(array, 1, num_items, cmp);
440 }
441
450 T &insert(const T & key)
451 {
452 ah_overflow_error_if(num_items >= dim) << "Heap out of capacity";
453 return insert_ne(key);
454 }
455
463 T &insert(T && key)
464 {
465 ah_overflow_error_if(num_items >= dim) << "Heap out of capacity";
466 return insert_ne(std::move(key));
467 }
468
475 T &put(const T & key) { return insert(key); }
476
483 T &append(const T & key) { return insert(key); }
484
491 T &put(T && key) { return insert(std::move(key)); }
492
499 T &append(T && key) { return insert(std::move(key)); }
500
510 {
511 ah_underflow_error_if(num_items == 0) << "Heap is empty";
512
513 T ret_val = array[1];
514 array[1] = array[num_items--];
515 if (num_items > 0)
517 return ret_val;
518 }
519
522 {
523 return getMin();
524 }
525
528 {
529 return getMin();
530 }
531
533 [[nodiscard]] constexpr size_t size() const noexcept { return num_items; }
534
536 [[nodiscard]] constexpr bool is_empty() const noexcept { return num_items == 0; }
537
542 [[nodiscard]] constexpr size_t capacity() const noexcept { return dim; }
543
557 void update(T & data)
558 {
559 ah_underflow_error_if(num_items == 0) << "Heap is empty";
560
561 assert(&data >= array + 1 and &data <= array + num_items);
562
563 const auto i = static_cast<size_t>(&data - array);
565 }
566
575 void remove(T & item)
576 {
577 ah_underflow_error_if(num_items == 0) << "Heap is empty";
578
579 assert(&item >= array + 1 and &item <= array + num_items);
580
581 const auto idx = static_cast<size_t>(&item - array);
582 if (idx == num_items)
583 {
584 --num_items;
585 return;
586 }
587
588 array[idx] = std::move(array[num_items--]);
589 sift_down_up(array, 1, idx, num_items, cmp);
590 }
591
599 T &operator [](const size_t i)
600 {
601 return array[i];
602 }
603
609 const T &operator [](const size_t i) const
610 {
611 return array[i];
612 }
613
614 struct Iterator : public Array_Iterator<T>
615 {
617 : Array_Iterator<T>(no_exception_ctor, h.array + 1, h.dim, h.num_items)
618 { /* empty */
619 }
620 };
621
622 private:
623 // superfast array traversal
624 template <class Operation>
626 {
627 for (size_t i = 1; i <= num_items; ++i)
628 if (not operation(array[i]))
629 return false;
630
631 return true;
632 }
633
634 public:
644 template <class Operation>
646 {
647 return const_cast<ArrayHeap &>(*this).traverse_impl(operation);
648 }
649
656 template <class Operation>
658 {
659 return traverse_impl(operation);
660 }
661
668 template <class Operation>
670 {
671 return const_cast<ArrayHeap &>(*this).traverse_impl(operation);
672 }
673
680 template <class Operation>
682 {
683 return traverse_impl(operation);
684 }
685 };
686} // end namespace Aleph
687# endif /* TPL_ARRAYHEAP_H */
Variadic constructor macros for containers.
Container traversal and functional operation mixins.
Exception handling system with formatted messages for Aleph-w.
#define ah_underflow_error_if(C)
Throws std::underflow_error if condition holds.
Definition ah-errors.H:368
#define ah_overflow_error_if(C)
Throws std::overflow_error if condition holds.
Definition ah-errors.H:463
#define ah_invalid_argument_if(C)
Throws std::invalid_argument if condition holds.
Definition ah-errors.H:639
Debug assertion and warning utilities.
Core definitions, constants, and utility macros for Aleph-w.
@ no_exception_ctor
Definition ahDefs.H:72
DRY (Don't Repeat Yourself) utilities and macros.
#define Special_Ctors(Set_Type, Type)
Generates special constructors for containers.
Definition ahDry.H:113
Standard functor implementations and comparison objects.
General utility functions and helpers.
Iterator wrapper for C++ raw arrays and circular buffers.
long double h
Definition btreepic.C:154
Fixed-capacity binary heap backed by a raw array.
T & insert_ne(T &&key)
Insert an element without checking capacity (move overload).
T & put(const T &key)
Synonym for insert().
bool traverse(Operation &&operation=Operation())
Traverse all elements (forwarding overload).
T & insert(const T &key)
Insert an element into the heap.
T & insert_ne(const T &key)
Insert an element without checking capacity.
ArrayHeap(ArrayHeap &&h) noexcept
const T & top() const
Return a const reference to the minimum element.
constexpr bool is_empty() const noexcept
Return true if the heap is empty.
T & append(const T &key)
Synonym for insert().
ArrayHeap(const ArrayHeap &h)
bool traverse_impl(Operation &operation)
void swap(ArrayHeap &h) noexcept
Swap all state with another heap.
bool traverse(Operation &operation)
Traverse all elements.
T & append(T &&key)
Synonym for insert() (move overload).
void update(T &data)
Update the priority of an element stored in the heap.
bool traverse(Operation &operation) const
Traverse all elements (const overload).
ArrayHeap(const size_t d=1024, Compare cmp_fct=Compare())
Construct an empty heap with internal storage.
constexpr size_t capacity() const noexcept
Return the maximum number of elements that can be stored.
ArrayHeap(T *ptr, const size_t &d, Compare cmp_fct=Compare())
Construct an empty heap using an external buffer.
T getMin()
Remove the smallest element in the heap and return a copy of its value.
T & put(T &&key)
Synonym for insert() (move overload).
static size_t r_index(const size_t &i)
T & top()
Return a mutable reference to the minimum element.
virtual ~ArrayHeap()
Destructor.
void allocate_storage(const size_t new_dim)
Allocate internal storage and reset the heap.
constexpr size_t size() const noexcept
Return the number of elements currently stored.
void remove(T &item)
Remove an element from the heap given a reference to it.
T & operator[](const size_t i)
Return a mutable reference to the i-th entry (1-based).
T & insert(T &&key)
Insert an element into the heap (move overload).
ArrayHeap & operator=(const ArrayHeap &h)
bool traverse(Operation &&operation=Operation()) const
Traverse all elements (const forwarding overload).
Iterator wrapper for C++ raw arrays.
Definition array_it.H:77
Performs order reversal of Compare by swapping operands.
Equality test for containers.
Definition ah-dry.H:1534
Common methods to the Aleph-w ( ) containers.
Definition ah-dry.H:548
Aleph::DynList< __T > maps(Operation &op) const
Map the elements of the container.
Definition ah-dry.H:904
Common sequential searching methods on containers.
Definition ah-dry.H:164
Mixin that adds STL begin()/end() and cbegin()/cend() to Aleph containers.
int cmp(const __gmp_expr< T, U > &expr1, const __gmp_expr< V, W > &expr2)
Definition gmpfrxx.h:4118
Singly linked list implementations with head-tail access.
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
void sift_down_up(T *ptr, const size_t l, const size_t i, const size_t r, Compare &cmp)
Restore the heap property by sifting down and then sifting up.
size_t l_index(const size_t i)
Map a binary heap index to the index of its left child.
Definition ahUtils.H:213
void sift_down(T *ptr, const size_t l, const size_t r, Compare &cmp)
Restore the heap property by moving the element at position l downwards.
void heapsort(T *array, const size_t n, const Compare &cmp=Compare())
Sort an array using the heapsort algorithm.
void faster_heapsort(T *array, const size_t n, const Compare &cmp=Compare())
Optimized version of heapsort.
std::decay_t< typename HeadC::Item_Type > T
Definition ah-zip.H:107
size_t u_index(const size_t &i)
Map a binary heap index to the index of its parent.
Definition ahUtils.H:199
bool valid_heap(T *array, const size_t l, const size_t r, const Compare &cmp=Compare())
Check whether a range satisfies the heap property.
T & sift_up(T *ptr, const size_t l, const size_t r, Compare &cmp)
Restore the heap property by moving the element at position r upwards.
DynList< T > maps(const C &c, Op op)
Classic map operation.
Iterator(const ArrayHeap &h) noexcept
Generic list of items stored in a container.
Definition ah-dry.H:1501
Dynamic doubly linked list implementation.
DynList< int > l