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 <ah-concepts.H>
51#include <algorithm>
52#include <cstddef>
53#include <stdexcept>
54#include <utility>
55
56#include <ahFunction.H>
57#include <ahUtils.H>
58#include <ahDefs.H>
59#include <ahAssert.H>
60#include <array_it.H>
61#include <htlist.H>
62#include <tpl_dynDlist.H>
63#include <ah-args-ctor.H>
64#include <ahDry.H>
65#include <ah-dry.H>
66#include <ah-errors.H>
67
68namespace Aleph
69{
84 template <typename T, class Compare>
85 inline
86 T &sift_up(T *ptr, const size_t l, const size_t r, Compare & cmp)
87 {
88 size_t i = r;
89 for (size_t p; i > l; i = p)
90 {
91 p = u_index(i); // parent index (p = i / 2)
92
93 // Prefetch grandparent for next iteration
94 if (const size_t gp = u_index(p); gp >= l)
95 __builtin_prefetch(&ptr[gp], 0, 1);
96
97 if (cmp(ptr[p], ptr[i])) [[likely]] // does the heap property hold?
98 return ptr[i]; // yes, the entire range is already a heap
99
100 std::swap(ptr[p], ptr[i]); // swap nodes and restore level p
101 }
102
103 return ptr[i];
104 }
105
119 template <typename T, class Compare>
120 inline
121 void sift_down(T *ptr, const size_t l, const size_t r, Compare & cmp)
122 {
123 size_t i = l;
124 while (true)
125 {
126 size_t c = l_index(i); // left child index (c = 2 * i)
127 if (c > r) [[unlikely]] // does it have a left child?
128 return; // no ==> stop
129
130 // Prefetch grandchildren for next iteration
131 if (const size_t gc = l_index(c); gc <= r)
132 __builtin_prefetch(&ptr[gc], 0, 1);
133
134 if (c + 1 <= r) // does it have a right child?
135 if (cmp(ptr[c + 1], ptr[c])) // yes ==> pick the smaller child
136 c++;
137
138 if (cmp(ptr[i], ptr[c])) [[likely]] // does the heap property hold?
139 return; // yes ==> stop
140
141 std::swap(ptr[c], ptr[i]);
142 i = c;
143 }
144 }
145
159 template <typename T, class Compare>
160 inline
161 void sift_down_up(T *ptr, const size_t l, const size_t i, const size_t r,
162 Compare & cmp)
163 {
164 sift_down<T, Compare>(ptr, i, r, cmp);
165 sift_up<T, Compare>(ptr, l, i, cmp);
166 }
167
183 template <typename T, class Compare = Aleph::less<T>>
185 inline
186 void heapsort(T *array, const size_t n, const Compare & cmp = Compare())
187 {
189
190 --array; // shift backwards so array[1] is the first element
191 for (size_t i = 2; i <= n; ++i)
193 for (size_t i = n; i > 1; --i)
194 {
195 std::swap(array[1], array[i]); // place the i-th item at the root
197 }
198 }
199
215 template <typename T, class Compare = Aleph::less<T>>
217 inline
218 void faster_heapsort(T *array, const size_t n, const Compare & cmp = Compare())
219 {
221
222 --array; // shift backwards so array[1] is the first element
223 for (size_t i = n / 2; i >= 1; --i)
224 sift_down(array, i, n, inv_cmp);
225 for (size_t i = n; i > 1; --i)
226 {
227 std::swap(array[1], array[i]); // place the i-th item at the root
228 sift_down(array, 1, i - 1, inv_cmp);
229 }
230 }
231
243 template <typename T, class Compare = Aleph::less<T>>
245 bool valid_heap(T *array, const size_t l, const size_t r,
246 const Compare & cmp = Compare())
247 {
248 size_t i;
249 for (i = l_index(l) /* i = 2*l */; i <= r; i++)
250 if (cmp(array[i], array[u_index(i)]))
251 break;
252 return i > r;
253 }
254
267 template <typename T, class Compare = Aleph::less<T>>
269 class ArrayHeap : public LocateFunctions<ArrayHeap<T, Compare>, T>,
270 public FunctionalMethods<ArrayHeap<T, Compare>, T>,
271 public GenericItems<ArrayHeap<T, Compare>, T>,
272 public EqualToMethod<ArrayHeap<T, Compare>>,
273 public StlAlephIterator<ArrayHeap<T, Compare>>
274 {
275 T *array = nullptr;
276 mutable size_t dim = 0;
277 size_t num_items = 0;
278
279 mutable bool array_allocated = false;
280
281 Compare cmp;
282
283 static size_t r_index(const size_t & i)
284 {
285 return (i << 1) + 1; // multiply i by 2 and add 1
286 }
287
288 public:
294 void allocate_storage(const size_t new_dim)
295 {
296 ah_invalid_argument_if(new_dim == 0) << "Heap capacity must be positive";
297
298 T *ptr = new T[new_dim + 1];
299 if (array_allocated)
300 delete [] array;
301
302 array = ptr;
303 dim = new_dim;
304 num_items = 0;
305 array_allocated = true;
306 }
307
312 void swap(ArrayHeap & h) noexcept
313 {
314 std::swap(array, h.array);
315 std::swap(dim, h.dim);
316 std::swap(num_items, h.num_items);
317 std::swap(array_allocated, h.array_allocated);
318 std::swap(cmp, h.cmp);
319 }
320
321 using Item_Type = T;
322
323 using Key_Type = T;
324
326
333 ArrayHeap(const size_t d = 1024, Compare cmp_fct = Compare())
334 : array(nullptr), cmp(cmp_fct)
335 {
337 }
338
348 ArrayHeap(T *ptr, const size_t & d, Compare cmp_fct = Compare())
349 : array(ptr), dim(d), cmp(cmp_fct)
350 {
351 ah_invalid_argument_if(ptr == nullptr or d == 0) << "ArrayHeap requires non-null buffer";
352 }
353
355 : array(nullptr), cmp(h.cmp)
356 {
357 allocate_storage(h.dim);
358 num_items = h.num_items;
359 for (size_t i = 1; i <= num_items; ++i)
360 array[i] = h.array[i];
361 }
362
364 : cmp(h.cmp)
365 {
366 swap(h);
367 }
368
370 {
371 if (this == &h)
372 return *this;
373
374 if (dim < h.dim)
375 allocate_storage(h.dim);
376
377 num_items = h.num_items;
378 for (size_t i = 1; i <= num_items; ++i)
379 array[i] = h.array[i];
380 cmp = h.cmp;
381
382 return *this;
383 }
384
386 noexcept
387 {
388 swap(h);
389 return *this;
390 }
391
393 virtual ~ArrayHeap()
394 {
395 if (array_allocated and array != nullptr)
396 delete [] array;
397 }
398
404 {
405 ah_underflow_error_if(num_items == 0) << "Heap is empty";
406
407 return array[1];
408 }
409
414 const T &top() const
415 {
416 ah_underflow_error_if(num_items == 0) << "Heap is empty";
417
418 return array[1];
419 }
420
428 T &insert_ne(const T & key)
429 {
430 array[++num_items] = key; // place the new element
431 return sift_up(array, 1, num_items, cmp);
432 }
433
441 T &insert_ne(T && key)
442 {
443 array[++num_items] = std::move(key); // place the new element
444 return sift_up(array, 1, num_items, cmp);
445 }
446
455 T &insert(const T & key)
456 {
457 ah_overflow_error_if(num_items >= dim) << "Heap out of capacity";
458 return insert_ne(key);
459 }
460
468 T &insert(T && key)
469 {
470 ah_overflow_error_if(num_items >= dim) << "Heap out of capacity";
471 return insert_ne(std::move(key));
472 }
473
480 T &put(const T & key) { return insert(key); }
481
488 T &append(const T & key) { return insert(key); }
489
496 T &put(T && key) { return insert(std::move(key)); }
497
504 T &append(T && key) { return insert(std::move(key)); }
505
515 {
516 ah_underflow_error_if(num_items == 0) << "Heap is empty";
517
518 T ret_val = array[1];
519 array[1] = array[num_items--];
520 if (num_items > 0)
522 return ret_val;
523 }
524
527 {
528 return getMin();
529 }
530
533 {
534 return getMin();
535 }
536
538 [[nodiscard]] constexpr size_t size() const noexcept { return num_items; }
539
541 [[nodiscard]] constexpr bool is_empty() const noexcept { return num_items == 0; }
542
547 [[nodiscard]] constexpr size_t capacity() const noexcept { return dim; }
548
562 void update(T & data)
563 {
564 ah_underflow_error_if(num_items == 0) << "Heap is empty";
565
566 assert(&data >= array + 1 and &data <= array + num_items);
567
568 const auto i = static_cast<size_t>(&data - array);
570 }
571
580 void remove(T & item)
581 {
582 ah_underflow_error_if(num_items == 0) << "Heap is empty";
583
584 assert(&item >= array + 1 and &item <= array + num_items);
585
586 const auto idx = static_cast<size_t>(&item - array);
587 if (idx == num_items)
588 {
589 --num_items;
590 return;
591 }
592
593 array[idx] = std::move(array[num_items--]);
594 sift_down_up(array, 1, idx, num_items, cmp);
595 }
596
604 T &operator [](const size_t i)
605 {
606 return array[i];
607 }
608
614 const T &operator [](const size_t i) const
615 {
616 return array[i];
617 }
618
619 struct Iterator : public Array_Iterator<T>
620 {
622 : Array_Iterator<T>(no_exception_ctor, h.array + 1, h.dim, h.num_items)
623 { /* empty */
624 }
625 };
626
627 private:
628 // superfast array traversal
629 template <class Operation>
631 {
632 for (size_t i = 1; i <= num_items; ++i)
633 if (not operation(array[i]))
634 return false;
635
636 return true;
637 }
638
639 public:
649 template <class Operation>
651 {
652 return const_cast<ArrayHeap &>(*this).traverse_impl(operation);
653 }
654
661 template <class Operation>
663 {
664 return traverse_impl(operation);
665 }
666
673 template <class Operation>
675 {
676 return const_cast<ArrayHeap &>(*this).traverse_impl(operation);
677 }
678
685 template <class Operation>
687 {
688 return traverse_impl(operation);
689 }
690 };
691} // end namespace Aleph
692# endif /* TPL_ARRAYHEAP_H */
Variadic constructor macros for containers.
C++20 concepts hub: comparison, BST policy, and Aleph container concepts.
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:373
#define ah_overflow_error_if(C)
Throws std::overflow_error if condition holds.
Definition ah-errors.H:468
#define ah_invalid_argument_if(C)
Throws std::invalid_argument if condition holds.
Definition ah-errors.H:644
Debug assertion and warning utilities.
Core definitions, constants, and utility macros for Aleph-w.
@ no_exception_ctor
Definition ahDefs.H:74
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:85
Performs order reversal of Compare by swapping operands.
Equality test for containers.
Definition ah-dry.H:1959
Common methods to the Aleph-w ( ) containers.
Definition ah-dry.H:658
and
Conditional mapping of the elements of the container.
Definition ah-dry.H:1137
Common sequential searching methods on containers.
Definition ah-dry.H:200
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:4129
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
Definition Blossom.H:466
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:217
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.
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.
std::decay_t< typename HeadC::Item_Type > T
Definition ah-zip.H:105
size_t u_index(const size_t &i)
Map a binary heap index to the index of its parent.
Definition ahUtils.H:203
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.
Iterator(const ArrayHeap &h) noexcept
Generic list of items stored in a container.
Definition ah-dry.H:1846
gsl_rng * r
Dynamic doubly linked list implementation.
DynList< int > l