Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_fibonacci_heap.H
Go to the documentation of this file.
1
2/*
3 Aleph_w
4
5 Data structures & Algorithms
6 version 2.0.0b
7 https://github.com/lrleon/Aleph-w
8
9 This file is part of Aleph-w library
10
11 Copyright (c) 2002-2026 Leandro Rabindranath Leon
12
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be included in all
21 copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 SOFTWARE.
30*/
31
32
44# ifndef TPL_FIBONACCI_HEAP_H
45# define TPL_FIBONACCI_HEAP_H
46
47# include <ah-concepts.H>
48# include <ahUtils.H>
49# include <ah-errors.H>
50# include <ahFunctional.H>
51# include <vector>
52# include <algorithm>
53# include <utility>
54
55namespace Aleph
56{
111 template <typename T, class Compare = Aleph::less<T>>
114 {
115 public:
127 struct Node
128 {
130 Node *parent = nullptr;
131 Node *child = nullptr;
132 Node *left = this;
133 Node *right = this;
134 size_t degree = 0;
135 bool mark = false;
136
138 explicit Node(const T & d) : data(d) {}
139
141 explicit Node(T && d) noexcept(std::is_nothrow_move_constructible_v<T>)
142 : data(std::move(d)) {}
143
155 template <typename Arg, typename... Args>
156 requires ((sizeof...(Args) >= 1) or
157 (not std::is_same_v<std::decay_t<Arg>, T> and
158 not std::is_same_v<std::decay_t<Arg>, Node>))
159 explicit Node(Arg&& arg, Args&&... args)
160 : data(std::forward<Arg>(arg), std::forward<Args>(args)...) {}
161 };
162
163 private:
170 static constexpr size_t MAX_DEGREE = 128;
171
172 Node *min_node = nullptr;
173 size_t num_nodes = 0;
174 Compare cmp;
175
182 std::vector<Node *> consolidate_array_;
183
192 static void link(Node *y, Node *x)
193 {
194 // Remove y from root list
195 y->left->right = y->right;
196 y->right->left = y->left;
197
198 // Make y a child of x
199 y->parent = x;
200 if (x->child == nullptr)
201 {
202 x->child = y;
203 y->right = y;
204 y->left = y;
205 }
206 else
207 {
208 y->left = x->child;
209 y->right = x->child->right;
210 x->child->right->left = y;
211 x->child->right = y;
212 }
213
214 ++x->degree;
215 y->mark = false;
216 }
217
225 {
226 if (min_node == nullptr)
227 return;
228
229 // Use member vector to avoid repeated allocations
230 if (consolidate_array_.size() < MAX_DEGREE)
231 consolidate_array_.resize(MAX_DEGREE, nullptr);
232 else
233 std::fill(consolidate_array_.begin(), consolidate_array_.end(), nullptr);
234
235 // Collect all root nodes to iterate safely while modifying links
236 std::vector<Node *> root_nodes;
237 Node *curr = min_node;
238 do
239 {
240 root_nodes.push_back(curr);
241 curr = curr->right;
242 }
243 while (curr != min_node);
244
245 for (Node *w : root_nodes)
246 {
247 Node *x = w;
248 size_t d = x->degree;
249
250 while (d < MAX_DEGREE && consolidate_array_[d] != nullptr)
251 {
253 // Ensure x has the smaller key (maintains heap property)
254 if (cmp(y->data, x->data))
255 std::swap(x, y);
256
257 link(y, x);
258 consolidate_array_[d] = nullptr;
259 ++d;
260 }
261
262 if (d < MAX_DEGREE)
263 consolidate_array_[d] = x;
264 }
265
266 // Reconstruct root list and find new minimum
267 min_node = nullptr;
268 for (size_t i = 0; i < MAX_DEGREE; ++i)
269 {
270 if (consolidate_array_[i] != nullptr)
271 {
272 consolidate_array_[i]->parent = nullptr;
273 if (min_node == nullptr)
274 {
278 }
279 else
280 {
281 // Insert into root list
286
287 if (cmp(consolidate_array_[i]->data, min_node->data))
289 }
290 }
291 }
292 }
293
300 void cut(Node *x, Node *y)
301 {
302 // Remove x from the child list of y
303 if (x->right == x)
304 y->child = nullptr;
305 else
306 {
307 x->left->right = x->right;
308 x->right->left = x->left;
309 if (y->child == x)
310 y->child = x->right;
311 }
312 --y->degree;
313
314 // Add x to the root list
315 x->left = min_node;
316 x->right = min_node->right;
317 min_node->right->left = x;
318 min_node->right = x;
319 x->parent = nullptr;
320 x->mark = false;
321 }
322
333 {
334 while (y != nullptr)
335 {
336 Node *z = y->parent;
337 if (z == nullptr)
338 break;
339
340 if (not y->mark)
341 {
342 y->mark = true;
343 break;
344 }
345 cut(y, z);
346 y = z; // Continue with parent (iterative instead of recursive)
347 }
348 }
349
358 {
359 if (node == nullptr)
360 return;
361
362 // Break the circular list to avoid use-after-free when checking
363 // loop termination condition against a deleted node
364 node->left->right = nullptr;
365
366 Node *curr = node;
367 while (curr != nullptr)
368 {
369 Node *next = curr->right;
370 // Recursively delete children
371 if (curr->child != nullptr)
372 delete_all_nodes(curr->child);
373 delete curr;
374 curr = next;
375 }
376 }
377
384 {
385 node->parent = nullptr;
386 if (min_node == nullptr)
387 {
388 min_node = node;
389 node->left = node;
390 node->right = node;
391 }
392 else
393 {
394 node->left = min_node;
395 node->right = min_node->right;
396 min_node->right->left = node;
397 min_node->right = node;
398
399 if (cmp(node->data, min_node->data))
400 min_node = node;
401 }
402 }
403
404 public:
406 using value_type = T;
407
409 using key_compare = Compare;
410
412 using handle_type = Node *;
413
421 explicit Fibonacci_Heap(Compare compare = Compare()) noexcept
422 : cmp(compare)
423 {
425 }
426
436 template <typename... Args>
437 explicit Fibonacci_Heap(std::in_place_t, Args&&... args) noexcept
438 : cmp(std::forward<Args>(args)...)
439 {
441 }
442
449 {
450 clear();
451 }
452
455
458
468 : min_node(other.min_node),
469 num_nodes(other.num_nodes),
470 cmp(std::move(other.cmp)),
471 consolidate_array_(std::move(other.consolidate_array_))
472 {
473 other.min_node = nullptr;
474 other.num_nodes = 0;
475 }
476
486 {
487 if (this != &other)
488 {
489 clear();
490 min_node = other.min_node;
491 num_nodes = other.num_nodes;
492 cmp = std::move(other.cmp);
493 consolidate_array_ = std::move(other.consolidate_array_);
494 other.min_node = nullptr;
495 other.num_nodes = 0;
496 }
497 return *this;
498 }
499
507 void swap(Fibonacci_Heap & other) noexcept
508 {
509 std::swap(min_node, other.min_node);
510 std::swap(num_nodes, other.num_nodes);
511 std::swap(cmp, other.cmp);
512 std::swap(consolidate_array_, other.consolidate_array_);
513 }
514
527 [[nodiscard]] Node * insert(const T & val)
528 {
529 Node *node = new Node(val);
530 add_to_root_list(node);
531 ++num_nodes;
532 return node;
533 }
534
545 [[nodiscard]]Node * insert(T && val)
546 {
547 Node *node = new Node(std::move(val));
548 add_to_root_list(node);
549 ++num_nodes;
550 return node;
551 }
552
565 template <typename... Args>
567 {
568 Node *node = new Node(std::forward<Args>(args)...);
569 add_to_root_list(node);
570 ++num_nodes;
571 return node;
572 }
573
582 [[nodiscard]] const T & get_min() const
583 {
584 ah_underflow_error_if(is_empty()) << "Fibonacci_Heap::get_min: heap is empty";
585 return min_node->data;
586 }
587
598 {
599 return min_node;
600 }
601
614 {
615 ah_underflow_error_if(is_empty()) << "Fibonacci_Heap::extract_min: heap is empty";
616
617 Node *z = min_node;
618
619 // Add all children of z to the root list
620 if (z->child != nullptr)
621 {
622 // First, set all children's parent to nullptr
623 Node *child = z->child;
624 do
625 {
626 child->parent = nullptr;
627 child = child->right;
628 }
629 while (child != z->child);
630
631 // Splice the child list into the root list
632 Node *child_left = z->child->left;
633 Node *z_right = z->right;
634
635 z->right = z->child;
636 z->child->left = z;
639
640 z->child = nullptr;
641 }
642
643 // Remove z from root list
644 if (z == z->right)
645 {
646 // z was the only root
647 min_node = nullptr;
648 }
649 else
650 {
651 z->left->right = z->right;
652 z->right->left = z->left;
653 min_node = z->right;
654 consolidate();
655 }
656
657 --num_nodes;
658 T data = std::move(z->data);
659 delete z;
660 return data;
661 }
662
677 void decrease_key(Node *x, const T & k)
678 {
679 ah_invalid_argument_if(x == nullptr)
680 << "Fibonacci_Heap::decrease_key: null node pointer";
682 << "Fibonacci_Heap::decrease_key: new key is greater than current key";
683
684 x->data = k;
685 Node *y = x->parent;
686
687 if (y != nullptr && cmp(x->data, y->data))
688 {
689 cut(x, y);
691 }
692
693 if (cmp(x->data, min_node->data))
694 min_node = x;
695 }
696
703 void decrease_key(Node *x, T && k)
704 {
705 ah_invalid_argument_if(x == nullptr)
706 << "Fibonacci_Heap::decrease_key: null node pointer";
708 << "Fibonacci_Heap::decrease_key: new key is greater than current key";
709
710 x->data = std::move(k);
711 Node *y = x->parent;
712
713 if (y != nullptr && cmp(x->data, y->data))
714 {
715 cut(x, y);
717 }
718
719 if (cmp(x->data, min_node->data))
720 min_node = x;
721 }
722
736 [[nodiscard]] Node * update_key(Node *x, const T & k)
737 {
738 ah_invalid_argument_if(x == nullptr)
739 << "Fibonacci_Heap::update_key: null node pointer";
740
741 if (cmp(k, x->data))
742 {
743 // New key is smaller, use decrease_key
744 decrease_key(x, k);
745 return x;
746 }
747 if (cmp(x->data, k))
748 {
749 // New key is larger, delete and reinsert
750 delete_node(x);
751 return insert(k);
752 }
753 // Keys are equal, do nothing
754 return x;
755 }
756
770 {
771 ah_invalid_argument_if(x == nullptr)
772 << "Fibonacci_Heap::delete_node: null node pointer";
773
774 // Step 1: If x is not a root, cut it and perform cascading cuts
775 if (x->parent != nullptr)
776 {
777 Node *parent = x->parent; // Save parent BEFORE cut
778 cut(x, parent);
779 cascading_cut(parent); // Use saved parent
780 }
781
782 // Step 2: Make x the minimum (by temporarily pointing min_node to it)
783 min_node = x;
784
785 // Step 3: Extract x (which is now the "minimum")
786 // We need to do extract_min logic but without returning data
787 if (x->child != nullptr)
788 {
789 Node *child = x->child;
790 do
791 {
792 child->parent = nullptr;
793 child = child->right;
794 }
795 while (child != x->child);
796
797 // Splice children into root list
798 Node *child_left = x->child->left;
799 Node *x_right = x->right;
800
801 if (x == x->right)
802 {
803 // x was alone, children become the root list
804 min_node = x->child;
805 }
806 else
807 {
808 x->right = x->child;
809 x->child->left = x;
812 }
813 }
814
815 // Remove x from root list
816 if (x == x->right)
817 {
818 // x was alone in root list
819 if (min_node == x)
820 min_node = nullptr; // x had no children either
821 else
822 consolidate(); // x had children, need to find true minimum
823 }
824 else
825 {
826 x->left->right = x->right;
827 x->right->left = x->left;
828 if (min_node == x)
829 min_node = x->right;
830 consolidate();
831 }
832
833 --num_nodes;
834 delete x;
835 }
836
850 {
851 if (&other == this || other.is_empty())
852 return;
853
854 if (is_empty())
855 {
856 min_node = other.min_node;
857 num_nodes = other.num_nodes;
858 }
859 else
860 {
861 // Concatenate root lists
863 Node *other_left = other.min_node->left;
864
865 min_node->right = other.min_node;
866 other.min_node->left = min_node;
869
870 // Update minimum if necessary
871 if (cmp(other.min_node->data, min_node->data))
872 min_node = other.min_node;
873
874 num_nodes += other.num_nodes;
875 }
876
877 // Clear the other heap (nodes now belong to us)
878 other.min_node = nullptr;
879 other.num_nodes = 0;
880 }
881
891 {
892 merge(other);
893 }
894
903 {
904 return min_node == nullptr;
905 }
906
915 {
916 return num_nodes;
917 }
918
927 {
928 if (min_node != nullptr)
929 {
931 min_node = nullptr;
932 num_nodes = 0;
933 }
934 }
935
937 {
938 return is_empty();
939 }
940
941 void pop()
942 {
943 extract_min();
944 }
945
946 [[nodiscard]] const T & top() const
947 {
948 return get_min();
949 }
950
956 [[nodiscard]] Compare key_comp() const
957 {
958 return cmp;
959 }
960 };
961
967 template <typename T, class Compare>
969 {
970 a.swap(b);
971 }
972
973} // namespace Aleph
974
975# endif // TPL_FIBONACCI_HEAP_H
C++20 concepts hub: comparison, BST policy, and Aleph container concepts.
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_domain_error_if(C)
Throws std::domain_error if condition holds.
Definition ah-errors.H:527
#define ah_invalid_argument_if(C)
Throws std::invalid_argument if condition holds.
Definition ah-errors.H:644
Functional programming utilities for Aleph-w containers.
General utility functions and helpers.
long double w
Definition btreepic.C:153
Implementation of a Fibonacci Heap priority queue.
void swap(Fibonacci_Heap &other) noexcept
Swaps contents with another heap.
static constexpr size_t MAX_DEGREE
Maximum degree tracked during consolidation.
Node * min_node
Pointer to the current minimum root.
Fibonacci_Heap(Compare compare=Compare()) noexcept
Default constructor.
const T & get_min() const
Returns the minimum element without removing it.
void swap(Fibonacci_Heap< T, Compare > &a, Fibonacci_Heap< T, Compare > &b) noexcept
Swaps two Fibonacci heaps.
Fibonacci_Heap & operator=(Fibonacci_Heap &&other) noexcept
Move assignment operator.
Node * insert(T &&val)
Inserts a new element (move).
Node * get_min_node() const noexcept
Returns a pointer to the minimum node.
Fibonacci_Heap & operator=(const Fibonacci_Heap &)=delete
Copy assignment is disabled (use merge or manual copy)
Fibonacci_Heap(Fibonacci_Heap &&other) noexcept
Move constructor.
Compare key_comp() const
Returns the comparison functor.
Compare cmp
Comparison functor used to order nodes.
void clear() noexcept(std::is_nothrow_destructible_v< T >)
Removes all elements from the heap.
T value_type
Type alias for the element type.
void add_to_root_list(Node *node)
Adds a node to the root list.
void cascading_cut(Node *y)
Performs cascading cut operation.
Node * insert(const T &val)
Inserts a new element (copy).
void merge(Fibonacci_Heap &other)
Merges another heap into this one.
void decrease_key(Node *x, T &&k)
Decreases the key of a node (move version).
static void link(Node *y, Node *x)
Links two trees of the same degree.
bool empty() const noexcept
void cut(Node *x, Node *y)
Cuts a node from its parent and adds it to the root list.
std::vector< Node * > consolidate_array_
Reusable scratch array for Fibonacci_Heap::consolidate().
void consolidate()
Consolidates the root list after extract_min.
Node * emplace(Args &&... args)
Constructs and inserts an element in-place.
size_t size() const noexcept
Returns the number of elements in the heap.
T extract_min()
Extracts and returns the minimum element.
size_t num_nodes
Number of elements stored in the heap.
void merge(Fibonacci_Heap &&other)
Merges another heap into this one (rvalue version).
void delete_node(Node *x)
Deletes a specific node from the heap.
Node * update_key(Node *x, const T &k)
Updates the key of a node (increase or decrease).
Compare key_compare
Type alias for the comparison functor.
Fibonacci_Heap(std::in_place_t, Args &&... args) noexcept
Constructor with in-place comparator construction.
void decrease_key(Node *x, const T &k)
Decreases the key of a node.
void delete_all_nodes(Node *node)
Recursively deletes all nodes in a tree.
bool is_empty() const noexcept
Checks if the heap is empty.
Fibonacci_Heap(const Fibonacci_Heap &)=delete
Copy constructor is disabled (use merge or manual copy)
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
static mpfr_t y
Definition mpfr_mul_d.c:3
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
and
Check uniqueness with explicit hash + equality functors.
std::decay_t< typename HeadC::Item_Type > T
Definition ah-zip.H:105
void next()
Advance all underlying iterators (bounds-checked).
Definition ah-zip.H:171
STL namespace.
Represents a node in the Fibonacci Heap.
T data
The data stored in this node.
Node * parent
Parent node (nullptr if root)
bool mark
Has this node lost a child since becoming non-root?
size_t degree
Number of children.
Node * left
Left sibling in circular list.
Node(T &&d) noexcept(std::is_nothrow_move_constructible_v< T >)
Construct a node moving d into the internal storage.
Node(Arg &&arg, Args &&... args)
Perfect-forwarding constructor for in-place construction.
Node(const T &d)
Construct a node copying d into the internal storage.
Node * child
Pointer to one child (head of child list)
Node * right
Right sibling in circular list.
static int * k