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 <ahUtils.H>
48# include <ah-errors.H>
49# include <ahFunctional.H>
50# include <vector>
51# include <algorithm>
52# include <utility>
53
54namespace Aleph
55{
110 template <typename T, class Compare = Aleph::less<T>>
112 {
113 public:
125 struct Node
126 {
128 Node *parent = nullptr;
129 Node *child = nullptr;
130 Node *left = this;
131 Node *right = this;
132 size_t degree = 0;
133 bool mark = false;
134
136 explicit Node(const T & d) : data(d) {}
137
139 explicit Node(T && d) noexcept(std::is_nothrow_move_constructible_v<T>)
140 : data(std::move(d)) {}
141
153 template <typename Arg, typename... Args,
154 std::enable_if_t<(sizeof...(Args) >= 1) ||
155 (!std::is_same_v<std::decay_t<Arg>, T> &&
156 !std::is_same_v<std::decay_t<Arg>, Node>), int> = 0>
157 explicit Node(Arg&& arg, Args&&... args)
158 : data(std::forward<Arg>(arg), std::forward<Args>(args)...) {}
159 };
160
161 private:
168 static constexpr size_t MAX_DEGREE = 128;
169
170 Node *min_node = nullptr;
171 size_t num_nodes = 0;
172 Compare cmp;
173
180 std::vector<Node *> consolidate_array_;
181
190 static void link(Node *y, Node *x)
191 {
192 // Remove y from root list
193 y->left->right = y->right;
194 y->right->left = y->left;
195
196 // Make y a child of x
197 y->parent = x;
198 if (x->child == nullptr)
199 {
200 x->child = y;
201 y->right = y;
202 y->left = y;
203 }
204 else
205 {
206 y->left = x->child;
207 y->right = x->child->right;
208 x->child->right->left = y;
209 x->child->right = y;
210 }
211
212 ++x->degree;
213 y->mark = false;
214 }
215
223 {
224 if (min_node == nullptr)
225 return;
226
227 // Use member vector to avoid repeated allocations
228 if (consolidate_array_.size() < MAX_DEGREE)
229 consolidate_array_.resize(MAX_DEGREE, nullptr);
230 else
231 std::fill(consolidate_array_.begin(), consolidate_array_.end(), nullptr);
232
233 // Collect all root nodes to iterate safely while modifying links
234 std::vector<Node *> root_nodes;
235 Node *curr = min_node;
236 do
237 {
238 root_nodes.push_back(curr);
239 curr = curr->right;
240 }
241 while (curr != min_node);
242
243 for (Node *w : root_nodes)
244 {
245 Node *x = w;
246 size_t d = x->degree;
247
248 while (d < MAX_DEGREE && consolidate_array_[d] != nullptr)
249 {
251 // Ensure x has the smaller key (maintains heap property)
252 if (cmp(y->data, x->data))
253 std::swap(x, y);
254
255 link(y, x);
256 consolidate_array_[d] = nullptr;
257 ++d;
258 }
259
260 if (d < MAX_DEGREE)
261 consolidate_array_[d] = x;
262 }
263
264 // Reconstruct root list and find new minimum
265 min_node = nullptr;
266 for (size_t i = 0; i < MAX_DEGREE; ++i)
267 {
268 if (consolidate_array_[i] != nullptr)
269 {
270 consolidate_array_[i]->parent = nullptr;
271 if (min_node == nullptr)
272 {
276 }
277 else
278 {
279 // Insert into root list
284
285 if (cmp(consolidate_array_[i]->data, min_node->data))
287 }
288 }
289 }
290 }
291
298 void cut(Node *x, Node *y)
299 {
300 // Remove x from the child list of y
301 if (x->right == x)
302 y->child = nullptr;
303 else
304 {
305 x->left->right = x->right;
306 x->right->left = x->left;
307 if (y->child == x)
308 y->child = x->right;
309 }
310 --y->degree;
311
312 // Add x to the root list
313 x->left = min_node;
314 x->right = min_node->right;
315 min_node->right->left = x;
316 min_node->right = x;
317 x->parent = nullptr;
318 x->mark = false;
319 }
320
331 {
332 while (y != nullptr)
333 {
334 Node *z = y->parent;
335 if (z == nullptr)
336 break;
337
338 if (not y->mark)
339 {
340 y->mark = true;
341 break;
342 }
343 cut(y, z);
344 y = z; // Continue with parent (iterative instead of recursive)
345 }
346 }
347
356 {
357 if (node == nullptr)
358 return;
359
360 // Break the circular list to avoid use-after-free when checking
361 // loop termination condition against a deleted node
362 node->left->right = nullptr;
363
364 Node *curr = node;
365 while (curr != nullptr)
366 {
367 Node *next = curr->right;
368 // Recursively delete children
369 if (curr->child != nullptr)
370 delete_all_nodes(curr->child);
371 delete curr;
372 curr = next;
373 }
374 }
375
382 {
383 node->parent = nullptr;
384 if (min_node == nullptr)
385 {
386 min_node = node;
387 node->left = node;
388 node->right = node;
389 }
390 else
391 {
392 node->left = min_node;
393 node->right = min_node->right;
394 min_node->right->left = node;
395 min_node->right = node;
396
397 if (cmp(node->data, min_node->data))
398 min_node = node;
399 }
400 }
401
402 public:
404 using value_type = T;
405
407 using key_compare = Compare;
408
410 using handle_type = Node *;
411
419 explicit Fibonacci_Heap(Compare compare = Compare()) noexcept
420 : cmp(compare)
421 {
423 }
424
434 template <typename... Args>
435 explicit Fibonacci_Heap(std::in_place_t, Args&&... args) noexcept
436 : cmp(std::forward<Args>(args)...)
437 {
439 }
440
447 {
448 clear();
449 }
450
453
456
466 : min_node(other.min_node),
467 num_nodes(other.num_nodes),
468 cmp(std::move(other.cmp)),
469 consolidate_array_(std::move(other.consolidate_array_))
470 {
471 other.min_node = nullptr;
472 other.num_nodes = 0;
473 }
474
484 {
485 if (this != &other)
486 {
487 clear();
488 min_node = other.min_node;
489 num_nodes = other.num_nodes;
490 cmp = std::move(other.cmp);
491 consolidate_array_ = std::move(other.consolidate_array_);
492 other.min_node = nullptr;
493 other.num_nodes = 0;
494 }
495 return *this;
496 }
497
505 void swap(Fibonacci_Heap & other) noexcept
506 {
507 std::swap(min_node, other.min_node);
508 std::swap(num_nodes, other.num_nodes);
509 std::swap(cmp, other.cmp);
510 std::swap(consolidate_array_, other.consolidate_array_);
511 }
512
525 [[nodiscard]] Node * insert(const T & val)
526 {
527 Node *node = new Node(val);
528 add_to_root_list(node);
529 ++num_nodes;
530 return node;
531 }
532
543 [[nodiscard]]Node * insert(T && val)
544 {
545 Node *node = new Node(std::move(val));
546 add_to_root_list(node);
547 ++num_nodes;
548 return node;
549 }
550
563 template <typename... Args>
565 {
566 Node *node = new Node(std::forward<Args>(args)...);
567 add_to_root_list(node);
568 ++num_nodes;
569 return node;
570 }
571
580 [[nodiscard]] const T & get_min() const
581 {
582 ah_underflow_error_if(is_empty()) << "Fibonacci_Heap::get_min: heap is empty";
583 return min_node->data;
584 }
585
596 {
597 return min_node;
598 }
599
612 {
613 ah_underflow_error_if(is_empty()) << "Fibonacci_Heap::extract_min: heap is empty";
614
615 Node *z = min_node;
616
617 // Add all children of z to the root list
618 if (z->child != nullptr)
619 {
620 // First, set all children's parent to nullptr
621 Node *child = z->child;
622 do
623 {
624 child->parent = nullptr;
625 child = child->right;
626 }
627 while (child != z->child);
628
629 // Splice the child list into the root list
630 Node *child_left = z->child->left;
631 Node *z_right = z->right;
632
633 z->right = z->child;
634 z->child->left = z;
635 child_left->right = z_right;
636 z_right->left = child_left;
637
638 z->child = nullptr;
639 }
640
641 // Remove z from root list
642 if (z == z->right)
643 {
644 // z was the only root
645 min_node = nullptr;
646 }
647 else
648 {
649 z->left->right = z->right;
650 z->right->left = z->left;
651 min_node = z->right;
652 consolidate();
653 }
654
655 --num_nodes;
656 T data = std::move(z->data);
657 delete z;
658 return data;
659 }
660
675 void decrease_key(Node *x, const T & k)
676 {
677 ah_invalid_argument_if(x == nullptr)
678 << "Fibonacci_Heap::decrease_key: null node pointer";
680 << "Fibonacci_Heap::decrease_key: new key is greater than current key";
681
682 x->data = k;
683 Node *y = x->parent;
684
685 if (y != nullptr && cmp(x->data, y->data))
686 {
687 cut(x, y);
689 }
690
691 if (cmp(x->data, min_node->data))
692 min_node = x;
693 }
694
701 void decrease_key(Node *x, T && k)
702 {
703 ah_invalid_argument_if(x == nullptr)
704 << "Fibonacci_Heap::decrease_key: null node pointer";
706 << "Fibonacci_Heap::decrease_key: new key is greater than current key";
707
708 x->data = std::move(k);
709 Node *y = x->parent;
710
711 if (y != nullptr && cmp(x->data, y->data))
712 {
713 cut(x, y);
715 }
716
717 if (cmp(x->data, min_node->data))
718 min_node = x;
719 }
720
734 [[nodiscard]] Node * update_key(Node *x, const T & k)
735 {
736 ah_invalid_argument_if(x == nullptr)
737 << "Fibonacci_Heap::update_key: null node pointer";
738
739 if (cmp(k, x->data))
740 {
741 // New key is smaller, use decrease_key
742 decrease_key(x, k);
743 return x;
744 }
745 if (cmp(x->data, k))
746 {
747 // New key is larger, delete and reinsert
748 delete_node(x);
749 return insert(k);
750 }
751 // Keys are equal, do nothing
752 return x;
753 }
754
768 {
769 ah_invalid_argument_if(x == nullptr)
770 << "Fibonacci_Heap::delete_node: null node pointer";
771
772 // Step 1: If x is not a root, cut it and perform cascading cuts
773 if (x->parent != nullptr)
774 {
775 Node *parent = x->parent; // Save parent BEFORE cut
776 cut(x, parent);
777 cascading_cut(parent); // Use saved parent
778 }
779
780 // Step 2: Make x the minimum (by temporarily pointing min_node to it)
781 min_node = x;
782
783 // Step 3: Extract x (which is now the "minimum")
784 // We need to do extract_min logic but without returning data
785 if (x->child != nullptr)
786 {
787 Node *child = x->child;
788 do
789 {
790 child->parent = nullptr;
791 child = child->right;
792 }
793 while (child != x->child);
794
795 // Splice children into root list
796 Node *child_left = x->child->left;
797 Node *x_right = x->right;
798
799 if (x == x->right)
800 {
801 // x was alone, children become the root list
802 min_node = x->child;
803 }
804 else
805 {
806 x->right = x->child;
807 x->child->left = x;
808 child_left->right = x_right;
809 x_right->left = child_left;
810 }
811 }
812
813 // Remove x from root list
814 if (x == x->right)
815 {
816 // x was alone in root list
817 if (min_node == x)
818 min_node = nullptr; // x had no children either
819 else
820 consolidate(); // x had children, need to find true minimum
821 }
822 else
823 {
824 x->left->right = x->right;
825 x->right->left = x->left;
826 if (min_node == x)
827 min_node = x->right;
828 consolidate();
829 }
830
831 --num_nodes;
832 delete x;
833 }
834
848 {
849 if (&other == this || other.is_empty())
850 return;
851
852 if (is_empty())
853 {
854 min_node = other.min_node;
855 num_nodes = other.num_nodes;
856 }
857 else
858 {
859 // Concatenate root lists
861 Node *other_left = other.min_node->left;
862
863 min_node->right = other.min_node;
864 other.min_node->left = min_node;
865 other_left->right = this_right;
866 this_right->left = other_left;
867
868 // Update minimum if necessary
869 if (cmp(other.min_node->data, min_node->data))
870 min_node = other.min_node;
871
872 num_nodes += other.num_nodes;
873 }
874
875 // Clear the other heap (nodes now belong to us)
876 other.min_node = nullptr;
877 other.num_nodes = 0;
878 }
879
889 {
890 merge(other);
891 }
892
901 {
902 return min_node == nullptr;
903 }
904
913 {
914 return num_nodes;
915 }
916
925 {
926 if (min_node != nullptr)
927 {
929 min_node = nullptr;
930 num_nodes = 0;
931 }
932 }
933
935 {
936 return is_empty();
937 }
938
939 void pop()
940 {
941 extract_min();
942 }
943
944 [[nodiscard]] const T & top() const
945 {
946 return get_min();
947 }
948
954 [[nodiscard]] Compare key_comp() const
955 {
956 return cmp;
957 }
958 };
959
965 template <typename T, class Compare>
967 {
968 a.swap(b);
969 }
970
971} // namespace Aleph
972
973# endif // TPL_FIBONACCI_HEAP_H
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_domain_error_if(C)
Throws std::domain_error if condition holds.
Definition ah-errors.H:522
#define ah_invalid_argument_if(C)
Throws std::invalid_argument if condition holds.
Definition ah-errors.H:639
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)
constexpr bool is_empty() const noexcept
Return true if list is empty.
Definition htlist.H:523
static mpfr_t y
Definition mpfr_mul_d.c:3
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
std::decay_t< typename HeadC::Item_Type > T
Definition ah-zip.H:107
void next()
Advance all underlying iterators (bounds-checked).
Definition ah-zip.H:175
DynList< T > maps(const C &c, Op op)
Classic map operation.
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(Arg &&arg, Args &&... args)
Perfect-forwarding constructor for in-place construction.
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(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.