Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
fibonacci_heap_test.cc
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
33
38# include <gtest/gtest.h>
39# include <numeric>
40# include <tpl_fibonacci_heap.H>
41# include <vector>
42# include <algorithm>
43# include <random>
44# include <string>
45# include <set>
46# include <chrono>
47# include <functional>
48
49using namespace Aleph;
50
51// =============================================================================
52// Test Fixtures
53// =============================================================================
54
55class FibonacciHeapTest : public ::testing::Test
56{
57protected:
59
60 void SetUp() override
61 {
62 // Fresh heap for each test
63 }
64};
65
66class FibonacciHeapWithDataTest : public ::testing::Test
67{
68protected:
70 std::vector<Fibonacci_Heap<int>::Node *> nodes;
71
72 void SetUp() override
73 {
74 // Insert some test data
75 for (int i = 10; i >= 1; --i)
76 nodes.push_back(heap.insert(i * 10)); // 100, 90, 80, ..., 10
77 }
78};
79
80// =============================================================================
81// Basic Construction Tests
82// =============================================================================
83
85{
87 EXPECT_TRUE(h.is_empty());
88 EXPECT_EQ(h.size(), 0u);
89 EXPECT_EQ(h.get_min_node(), nullptr);
90}
91
93{
96 max_heap.insert(10);
97 max_heap.insert(3);
98 EXPECT_EQ(max_heap.get_min(), 10); // Max heap, so "min" is actually max
99}
100
102{
104 h1.insert(5);
105 h1.insert(3);
106 h1.insert(7);
107
108 Fibonacci_Heap<int> h2(std::move(h1));
109
110 EXPECT_TRUE(h1.is_empty());
111 EXPECT_EQ(h1.size(), 0u);
112
113 EXPECT_FALSE(h2.is_empty());
114 EXPECT_EQ(h2.size(), 3u);
115 EXPECT_EQ(h2.get_min(), 3);
116}
117
119{
121 h1.insert(5);
122 h1.insert(3);
123
125 h2.insert(100);
126
127 h2 = std::move(h1);
128
129 EXPECT_TRUE(h1.is_empty());
130 EXPECT_EQ(h2.size(), 2u);
131 EXPECT_EQ(h2.get_min(), 3);
132}
133
135{
137 h.insert(5);
138 h.insert(3);
139
140 const auto original_size = h.size();
141 Fibonacci_Heap<int> tmp(std::move(h));
142 h = std::move(tmp);
143
144 EXPECT_EQ(h.size(), original_size);
145 EXPECT_EQ(h.get_min(), 3);
146}
147
148// =============================================================================
149// Insert Tests
150// =============================================================================
151
153{
154 auto node = heap.insert(42);
155
156 EXPECT_FALSE(heap.is_empty());
157 EXPECT_EQ(heap.size(), 1u);
158 EXPECT_EQ(heap.get_min(), 42);
159 EXPECT_EQ(node->data, 42);
160}
161
163{
164 heap.insert(10);
165 heap.insert(5);
166 heap.insert(15);
167 heap.insert(3);
168 heap.insert(8);
169
170 EXPECT_EQ(heap.size(), 5u);
171 EXPECT_EQ(heap.get_min(), 3);
172}
173
175{
176 for (int i = 100; i >= 1; --i)
177 heap.insert(i);
178
179 EXPECT_EQ(heap.size(), 100u);
180 EXPECT_EQ(heap.get_min(), 1);
181}
182
184{
185 for (int i = 1; i <= 100; ++i)
186 heap.insert(i);
187
188 EXPECT_EQ(heap.size(), 100u);
189 EXPECT_EQ(heap.get_min(), 1);
190}
191
193{
194 for (int i = 0; i < 10; ++i)
195 heap.insert(42);
196
197 EXPECT_EQ(heap.size(), 10u);
198 EXPECT_EQ(heap.get_min(), 42);
199
200 // All extractions should return 42
201 for (int i = 0; i < 10; ++i)
202 EXPECT_EQ(heap.extract_min(), 42);
203
204 EXPECT_TRUE(heap.is_empty());
205}
206
208{
209 std::string s = "hello world";
211
212 auto node = string_heap.insert(std::move(s));
213
214 EXPECT_EQ(node->data, "hello world");
215 EXPECT_TRUE(s.empty() || s != "hello world"); // s should be moved-from
216}
217
219{
221
222 auto node = pair_heap.emplace(42, "answer");
223
224 EXPECT_EQ(node->data.first, 42);
225 EXPECT_EQ(node->data.second, "answer");
226}
227
228// =============================================================================
229// Get Min Tests
230// =============================================================================
231
233{
234 EXPECT_THROW(heap.get_min(), std::underflow_error);
235}
236
238{
239 EXPECT_EQ(heap.get_min_node(), nullptr);
240}
241
243{
244 heap.insert(50);
245 EXPECT_EQ(heap.get_min(), 50);
246
247 heap.insert(30);
248 EXPECT_EQ(heap.get_min(), 30);
249
250 heap.insert(40);
251 EXPECT_EQ(heap.get_min(), 30);
252
253 heap.insert(10);
254 EXPECT_EQ(heap.get_min(), 10);
255
256 heap.insert(20);
257 EXPECT_EQ(heap.get_min(), 10);
258}
259
260// =============================================================================
261// Extract Min Tests
262// =============================================================================
263
265{
266 EXPECT_THROW(heap.extract_min(), std::underflow_error);
267}
268
270{
271 heap.insert(42);
272 int val = heap.extract_min();
273
274 EXPECT_EQ(val, 42);
275 EXPECT_TRUE(heap.is_empty());
276}
277
279{
280 heap.insert(30);
281 heap.insert(10);
282 heap.insert(20);
283
284 EXPECT_EQ(heap.extract_min(), 10);
285 EXPECT_EQ(heap.extract_min(), 20);
286 EXPECT_EQ(heap.extract_min(), 30);
287 EXPECT_TRUE(heap.is_empty());
288}
289
291{
292 std::vector<int> input = {50, 20, 80, 10, 90, 30, 70, 40, 60, 100};
293 for (int v : input)
294 heap.insert(v);
295
296 std::vector<int> extracted;
297 while (!heap.is_empty())
298 extracted.push_back(heap.extract_min());
299
300 std::vector<int> expected = input;
301 std::sort(expected.begin(), expected.end());
302
304}
305
307{
308 std::vector<int> input = {5, 3, 5, 1, 3, 5, 1, 3};
309 for (int v : input)
310 heap.insert(v);
311
312 std::vector<int> extracted;
313 while (!heap.is_empty())
314 extracted.push_back(heap.extract_min());
315
316 std::sort(input.begin(), input.end());
318}
319
320// =============================================================================
321// Decrease Key Tests
322// =============================================================================
323
325{
326 // nodes[9] has value 10 (the current minimum)
327 // nodes[0] has value 100
328 heap.decrease_key(nodes[0], 5);
329
330 EXPECT_EQ(heap.get_min(), 5);
331 EXPECT_EQ(nodes[0]->data, 5);
332}
333
335{
336 // nodes[1] has value 90
337 heap.decrease_key(nodes[1], 50);
338
339 EXPECT_EQ(heap.get_min(), 10); // Still 10
340 EXPECT_EQ(nodes[1]->data, 50);
341}
342
344{
345 // Decreasing to same value should work
346 heap.decrease_key(nodes[0], 100);
347 EXPECT_EQ(nodes[0]->data, 100);
348}
349
351{
352 auto node = heap.insert(50);
353 EXPECT_THROW(heap.decrease_key(node, 100), std::domain_error);
354}
355
357{
358 EXPECT_THROW(heap.decrease_key(nullptr, 10), std::invalid_argument);
359}
360
362{
363 // Build a heap that will have internal structure
364 for (int i = 1; i <= 20; ++i)
365 heap.insert(i);
366
367 // Extract some to build tree structure
368 for (int i = 0; i < 5; ++i)
369 heap.extract_min();
370
371 // Now decrease a key that should trigger cuts
372 auto node = heap.insert(100);
373 heap.decrease_key(node, 1); // Should become new minimum
374
375 EXPECT_EQ(heap.get_min(), 1);
376}
377
379{
380 // Insert elements and extract to create tree structure
381 std::vector<Fibonacci_Heap<int>::Node *> nodes;
382 for (int i = 1; i <= 100; ++i)
383 nodes.push_back(heap.insert(i * 10));
384
385 // Extract min multiple times to consolidate
386 for (int i = 0; i < 20; ++i)
387 heap.extract_min();
388
389 // Find remaining nodes and decrease their keys
390 // This should trigger cascading cuts
391 for (size_t i = 50; i < 60 && i < nodes.size(); ++i)
392 {
393 if (nodes[i]->data > 5)
394 heap.decrease_key(nodes[i], static_cast<int>(i));
395 }
396
397 // Verify heap property is maintained
398 std::vector<int> extracted;
399 while (!heap.is_empty())
400 extracted.push_back(heap.extract_min());
401
402 for (size_t i = 1; i < extracted.size(); ++i)
403 EXPECT_LE(extracted[i - 1], extracted[i]);
404}
405
407{
409 auto node = string_heap.insert("zzzzz");
410
411 std::string new_val = "aaaaa";
412 string_heap.decrease_key(node, std::move(new_val));
413
414 EXPECT_EQ(node->data, "aaaaa");
415}
416
417// =============================================================================
418// Update Key Tests
419// =============================================================================
420
422{
423 auto node = heap.insert(50);
424 auto result = heap.update_key(node, 30);
425
426 EXPECT_EQ(result, node);
427 EXPECT_EQ(node->data, 30);
428}
429
431{
432 heap.insert(30);
433 auto node = heap.insert(50);
434 heap.insert(70);
435
436 auto result = heap.update_key(node, 80);
437
438 // The result should contain the new value and heap should be consistent
439 // Note: The returned pointer may or may not be the same as node due to
440 // memory allocator reuse, so we don't check pointer equality
441 EXPECT_EQ(result->data, 80);
442 EXPECT_EQ(heap.size(), 3u);
443
444 // Verify heap order is maintained: 30, 70, 80
445 EXPECT_EQ(heap.extract_min(), 30);
446 EXPECT_EQ(heap.extract_min(), 70);
447 EXPECT_EQ(heap.extract_min(), 80);
448}
449
451{
452 auto node = heap.insert(50);
453 auto result = heap.update_key(node, 50);
454
455 EXPECT_EQ(result, node);
456 EXPECT_EQ(node->data, 50);
457}
458
460{
461 EXPECT_THROW(heap.update_key(nullptr, 10), std::invalid_argument);
462}
463
464// =============================================================================
465// Delete Node Tests
466// =============================================================================
467
469{
470 auto node = heap.insert(42);
471 heap.delete_node(node);
472
473 EXPECT_TRUE(heap.is_empty());
474}
475
477{
478 heap.insert(30);
479 auto min_node = heap.insert(10);
480 heap.insert(20);
481
482 heap.delete_node(min_node);
483
484 EXPECT_EQ(heap.size(), 2u);
485 EXPECT_EQ(heap.get_min(), 20);
486}
487
489{
490 heap.insert(10);
491 auto middle = heap.insert(20);
492 heap.insert(30);
493
494 heap.delete_node(middle);
495
496 EXPECT_EQ(heap.size(), 2u);
497 EXPECT_EQ(heap.get_min(), 10);
498 EXPECT_EQ(heap.extract_min(), 10);
499 EXPECT_EQ(heap.extract_min(), 30);
500}
501
503{
504 EXPECT_THROW(heap.delete_node(nullptr), std::invalid_argument);
505}
506
508{
509 // Create a complex tree structure
510 std::vector<Fibonacci_Heap<int>::Node *> nodes;
511 for (int i = 1; i <= 50; ++i)
512 nodes.push_back(heap.insert(i));
513
514 // Extract to consolidate
515 for (int i = 0; i < 10; ++i)
516 heap.extract_min();
517
518 // Delete some internal nodes
519 heap.delete_node(nodes[30]);
520 heap.delete_node(nodes[40]);
521 heap.delete_node(nodes[25]);
522
523 // Verify remaining elements
524 std::vector<int> extracted;
525 while (!heap.is_empty())
526 extracted.push_back(heap.extract_min());
527
528 // Should have 50 - 10 (extracted) - 3 (deleted) = 37 elements
529 EXPECT_EQ(extracted.size(), 37u);
530
531 // Should be sorted
532 for (size_t i = 1; i < extracted.size(); ++i)
533 EXPECT_LE(extracted[i - 1], extracted[i]);
534}
535
536// Test for bug: deleting a solitary root with children must consolidate
537// to find the true minimum among the children
539{
540 // Insert values: 10 will become root after extract, with children
541 (void)heap.insert(10);
542 (void)heap.insert(5);
543 (void)heap.insert(20);
544 (void)heap.insert(15);
545 (void)heap.insert(3);
546
547 // Extract minimum (3) - this triggers consolidation
548 // After this, the tree structure will have some nodes as children
549 EXPECT_EQ(heap.extract_min(), 3);
550
551 // Now extract 5 - more consolidation
552 EXPECT_EQ(heap.extract_min(), 5);
553
554 // At this point we have 10, 15, 20 remaining
555 // The structure may have 10 as root with children
556
557 // Insert a new minimum so we can control the structure
558 (void)heap.insert(1);
559
560 // Extract 1 to consolidate: 10, 15, 20 remain, possibly with 10 as root
561 EXPECT_EQ(heap.extract_min(), 1);
562
563 // Now delete the current minimum (should be 10)
564 // This tests deleting a node that may be alone with children
565 auto min_node = heap.get_min_node();
566 heap.delete_node(min_node);
567
568 // After deletion, heap should correctly identify the new minimum
569 EXPECT_EQ(heap.size(), 2u);
570
571 // The new minimum should be correctly found (not just any child)
572 int new_min = heap.get_min();
573 EXPECT_TRUE(new_min == 15 || new_min == 20);
574
575 // Verify we can extract both remaining elements in order
576 int first = heap.extract_min();
577 int second = heap.extract_min();
578 EXPECT_LT(first, second);
579 EXPECT_TRUE(heap.is_empty());
580}
581
582// More direct test: manually create scenario with solitary root + children
584{
585 // Create heap with nodes that will form a single tree
586 heap.insert(100); // Will be root
587 heap.insert(50);
588 heap.insert(200);
589 heap.insert(25);
590 heap.insert(10); // Will be minimum
591
592 // Extract to build tree structure
593 EXPECT_EQ(heap.extract_min(), 10);
594 EXPECT_EQ(heap.extract_min(), 25);
595
596 // Now 50 is minimum, 100 and 200 may be children or siblings
597 // Keep extracting until we have a small tree
598 EXPECT_EQ(heap.extract_min(), 50);
599
600 // Only 100 and 200 remain
601 EXPECT_EQ(heap.size(), 2u);
602
603 // Delete the minimum (100)
604 heap.delete_node(heap.get_min_node());
605
606 // Only 200 should remain
607 EXPECT_EQ(heap.size(), 1u);
608 EXPECT_EQ(heap.get_min(), 200);
609 EXPECT_EQ(heap.extract_min(), 200);
610 EXPECT_TRUE(heap.is_empty());
611}
612
614{
615 std::vector<Fibonacci_Heap<int>::Node *> nodes;
616 for (int i = 1; i <= 20; ++i)
617 nodes.push_back(heap.insert(i));
618
619 // Delete in random order
620 std::vector<size_t> indices(20);
621 std::iota(indices.begin(), indices.end(), 0);
622 std::random_device rd;
623 std::mt19937 g(rd());
624 std::shuffle(indices.begin(), indices.end(), g);
625
626 for (size_t idx : indices)
627 {
628 heap.delete_node(nodes[idx]);
629 }
630
631 EXPECT_TRUE(heap.is_empty());
632}
633
634// =============================================================================
635// Merge Tests
636// =============================================================================
637
639{
641 h1.merge(h2);
642
643 EXPECT_TRUE(h1.is_empty());
644 EXPECT_TRUE(h2.is_empty());
645}
646
648{
650 h2.insert(5);
651 h2.insert(3);
652
653 h1.merge(h2);
654
655 EXPECT_EQ(h1.size(), 2u);
656 EXPECT_EQ(h1.get_min(), 3);
657 EXPECT_TRUE(h2.is_empty());
658}
659
661{
663 h1.insert(5);
664 h1.insert(3);
665
666 h1.merge(h2);
667
668 EXPECT_EQ(h1.size(), 2u);
669 EXPECT_EQ(h1.get_min(), 3);
670}
671
673{
675
676 h1.insert(10);
677 h1.insert(5);
678 h1.insert(15);
679
680 h2.insert(3);
681 h2.insert(8);
682 h2.insert(12);
683
684 h1.merge(h2);
685
686 EXPECT_EQ(h1.size(), 6u);
687 EXPECT_EQ(h1.get_min(), 3);
688 EXPECT_TRUE(h2.is_empty());
689
690 // Verify all elements
691 std::vector<int> extracted;
692 while (!h1.is_empty())
693 extracted.push_back(h1.extract_min());
694
695 std::vector<int> expected = {3, 5, 8, 10, 12, 15};
697}
698
700{
702 h1.insert(10);
703
705 h2.insert(5);
706
707 h1.merge(std::move(h2));
708
709 EXPECT_EQ(h1.size(), 2u);
710 EXPECT_EQ(h1.get_min(), 5);
711}
712
714{
716
717 for (int i = 0; i < 1000; i += 2)
718 h1.insert(i);
719
720 for (int i = 1; i < 1000; i += 2)
721 h2.insert(i);
722
723 h1.merge(h2);
724
725 EXPECT_EQ(h1.size(), 1000u);
726
727 std::vector<int> extracted;
728 while (!h1.is_empty())
729 extracted.push_back(h1.extract_min());
730
731 for (int i = 0; i < 1000; ++i)
732 EXPECT_EQ(extracted[i], i);
733}
734
735// =============================================================================
736// Swap Tests
737// =============================================================================
738
740{
742
743 h1.insert(10);
744 h1.insert(5);
745
746 h2.insert(100);
747 h2.insert(50);
748 h2.insert(75);
749
750 h1.swap(h2);
751
752 EXPECT_EQ(h1.size(), 3u);
753 EXPECT_EQ(h1.get_min(), 50);
754
755 EXPECT_EQ(h2.size(), 2u);
756 EXPECT_EQ(h2.get_min(), 5);
757}
758
760{
762 h1.insert(10);
763
764 h1.swap(h2);
765
766 EXPECT_TRUE(h1.is_empty());
767 EXPECT_EQ(h2.size(), 1u);
768 EXPECT_EQ(h2.get_min(), 10);
769}
770
772{
774 h1.insert(5);
775 h2.insert(10);
776
777 Aleph::swap(h1, h2);
778
779 EXPECT_EQ(h1.get_min(), 10);
780 EXPECT_EQ(h2.get_min(), 5);
781}
782
783// =============================================================================
784// Clear Tests
785// =============================================================================
786
788{
789 heap.clear();
790 EXPECT_TRUE(heap.is_empty());
791}
792
794{
795 for (int i = 0; i < 100; ++i)
796 heap.insert(i);
797
798 heap.clear();
799
800 EXPECT_TRUE(heap.is_empty());
801 EXPECT_EQ(heap.size(), 0u);
802}
803
805{
806 heap.insert(10);
807 heap.insert(5);
808 heap.clear();
809
810 heap.insert(20);
811 heap.insert(15);
812
813 EXPECT_EQ(heap.size(), 2u);
814 EXPECT_EQ(heap.get_min(), 15);
815}
816
817// =============================================================================
818// Type Alias Tests
819// =============================================================================
820
822{
823 static_assert(std::is_same_v<Fibonacci_Heap<int>::value_type, int>);
824 static_assert(std::is_same_v<Fibonacci_Heap<std::string>::value_type, std::string>);
825}
826
828{
829 static_assert(std::is_same_v<Fibonacci_Heap<int>::handle_type, Fibonacci_Heap<int>::Node *>);
830}
831
832// =============================================================================
833// Max Heap Tests
834// =============================================================================
835
837{
839
840 max_heap.insert(10);
841 max_heap.insert(30);
842 max_heap.insert(20);
843
844 EXPECT_EQ(max_heap.get_min(), 30); // "min" is actually max
845 EXPECT_EQ(max_heap.extract_min(), 30);
846 EXPECT_EQ(max_heap.extract_min(), 20);
847 EXPECT_EQ(max_heap.extract_min(), 10);
848}
849
851{
853
854 auto n1 = max_heap.insert(10);
855 max_heap.insert(30);
856 max_heap.insert(20);
857
858 // In max heap, "decrease" means increase the value
859 max_heap.decrease_key(n1, 50);
860
861 EXPECT_EQ(max_heap.get_min(), 50);
862}
863
864// =============================================================================
865// Custom Type Tests
866// =============================================================================
867
868struct Point
869{
870 double x, y;
871 double distance() const { return x * x + y * y; }
872
873 bool operator<(const Point & other) const
874 {
875 return distance() < other.distance();
876 }
877};
878
880{
882
883 point_heap.insert({3.0, 4.0}); // distance = 25
884 point_heap.insert({1.0, 1.0}); // distance = 2
885 point_heap.insert({2.0, 2.0}); // distance = 8
886
887 EXPECT_DOUBLE_EQ(point_heap.get_min().distance(), 2.0);
888 EXPECT_DOUBLE_EQ(point_heap.extract_min().distance(), 2.0);
889 EXPECT_DOUBLE_EQ(point_heap.extract_min().distance(), 8.0);
890 EXPECT_DOUBLE_EQ(point_heap.extract_min().distance(), 25.0);
891}
892
894{
895 // Heap of (priority, value) pairs
897
898 pair_heap.insert({3, "three"});
899 pair_heap.insert({1, "one"});
900 pair_heap.insert({2, "two"});
901
902 EXPECT_EQ(pair_heap.extract_min().second, "one");
903 EXPECT_EQ(pair_heap.extract_min().second, "two");
904 EXPECT_EQ(pair_heap.extract_min().second, "three");
905}
906
907// =============================================================================
908// Stress Tests
909// =============================================================================
910
912{
914 constexpr int N = 100000;
915
916 for (int i = N; i >= 1; --i)
917 (void)heap.insert(i);
918
919 EXPECT_EQ(heap.size(), static_cast<size_t>(N));
920 EXPECT_EQ(heap.get_min(), 1);
921}
922
924{
926 constexpr int N = 10000;
927
928 for (int i = N; i >= 1; --i)
929 (void)heap.insert(i);
930
931 for (int i = 1; i <= N; ++i)
932 EXPECT_EQ(heap.extract_min(), i);
933
934 EXPECT_TRUE(heap.is_empty());
935}
936
938{
940 std::multiset<int> reference; // For verification
941 std::random_device rd;
942 std::mt19937 gen(42); // Fixed seed for reproducibility
943 std::uniform_int_distribution<> dis(1, 10000);
944
945 constexpr int N = 10000;
946
947 for (int i = 0; i < N; ++i)
948 {
949 int op = dis(gen) % 3;
950
951 if (op == 0 || reference.empty())
952 {
953 // Insert
954 int val = dis(gen);
955 (void)heap.insert(val);
956 reference.insert(val);
957 }
958 else if (op == 1)
959 {
960 // Extract min
961 int heap_min = heap.extract_min();
962 int ref_min = *reference.begin();
963 reference.erase(reference.begin());
965 }
966 else
967 {
968 // Get min
969 EXPECT_EQ(heap.get_min(), *reference.begin());
970 }
971 }
972
973 // Drain remaining
974 while (!heap.is_empty())
975 {
976 int heap_min = heap.extract_min();
977 int ref_min = *reference.begin();
978 reference.erase(reference.begin());
980 }
981}
982
984{
986 std::vector<Fibonacci_Heap<int>::Node *> nodes;
987 constexpr int N = 5000;
988
989 for (int i = 0; i < N; ++i)
990 nodes.push_back(heap.insert(i + N)); // Insert N, N+1, ..., 2N-1
991
992 // Extract some to create tree structure
993 for (int i = 0; i < N / 4; ++i)
994 heap.extract_min();
995
996 // Decrease remaining keys
997 int counter = 0;
998 for (size_t i = N / 4; i < N; ++i)
999 {
1000 if (nodes[i]->data > counter)
1001 {
1002 heap.decrease_key(nodes[i], counter);
1003 counter++;
1004 }
1005 }
1006
1007 // Verify heap property
1008 int prev = heap.extract_min();
1009 while (!heap.is_empty())
1010 {
1011 int curr = heap.extract_min();
1012 EXPECT_LE(prev, curr);
1013 prev = curr;
1014 }
1015}
1016
1018{
1020 std::vector<Fibonacci_Heap<int>::Node *> nodes;
1021 constexpr int N = 1000;
1022
1023 for (int i = 0; i < N; ++i)
1024 nodes.push_back(heap.insert(i));
1025
1026 // Delete every other node
1027 for (int i = 0; i < N; i += 2)
1028 heap.delete_node(nodes[i]);
1029
1030 EXPECT_EQ(heap.size(), static_cast<size_t>(N / 2));
1031
1032 // Verify remaining elements are odd numbers
1033 std::vector<int> extracted;
1034 while (!heap.is_empty())
1035 extracted.push_back(heap.extract_min());
1036
1037 EXPECT_EQ(extracted.size(), static_cast<size_t>(N / 2));
1038 for (size_t i = 0; i < extracted.size(); ++i)
1039 EXPECT_EQ(extracted[i], static_cast<int>(2 * i + 1));
1040}
1041
1043{
1044 std::vector<Fibonacci_Heap<int>> heaps(100);
1045
1046 // Insert into each heap
1047 for (int i = 0; i < 100; ++i)
1048 for (int j = 0; j < 100; ++j)
1049 heaps[i].insert(i * 100 + j);
1050
1051 // Merge all into first
1052 for (int i = 1; i < 100; ++i)
1053 heaps[0].merge(heaps[i]);
1054
1055 EXPECT_EQ(heaps[0].size(), 10000u);
1056
1057 // Verify sorted order
1058 int prev = heaps[0].extract_min();
1059 while (!heaps[0].is_empty())
1060 {
1061 int curr = heaps[0].extract_min();
1062 EXPECT_LE(prev, curr);
1063 prev = curr;
1064 }
1065}
1066
1067// =============================================================================
1068// Edge Case Tests
1069// =============================================================================
1070
1072{
1074
1075 heap.insert(-10);
1076 heap.insert(-5);
1077 heap.insert(-20);
1078 heap.insert(0);
1079 heap.insert(10);
1080
1081 EXPECT_EQ(heap.extract_min(), -20);
1082 EXPECT_EQ(heap.extract_min(), -10);
1083 EXPECT_EQ(heap.extract_min(), -5);
1084 EXPECT_EQ(heap.extract_min(), 0);
1085 EXPECT_EQ(heap.extract_min(), 10);
1086}
1087
1089{
1091
1092 heap.insert(std::numeric_limits<int>::max());
1093 heap.insert(0);
1094 heap.insert(std::numeric_limits<int>::min());
1095
1096 EXPECT_EQ(heap.extract_min(), std::numeric_limits<int>::min());
1097 EXPECT_EQ(heap.extract_min(), 0);
1098 EXPECT_EQ(heap.extract_min(), std::numeric_limits<int>::max());
1099}
1100
1102{
1104 auto node = heap.insert(42);
1105
1106 // Decrease key on single element
1107 heap.decrease_key(node, 10);
1108 EXPECT_EQ(heap.get_min(), 10);
1109
1110 // Delete single element
1111 heap.delete_node(node);
1112 EXPECT_TRUE(heap.is_empty());
1113}
1114
1116{
1118
1119 // Insert alternating min and max values
1120 for (int i = 0; i < 100; ++i)
1121 {
1122 if (i % 2 == 0)
1123 heap.insert(std::numeric_limits<int>::min() + i / 2);
1124 else
1125 heap.insert(std::numeric_limits<int>::max() - i / 2);
1126 }
1127
1128 // Should extract in sorted order
1129 int prev = heap.extract_min();
1130 while (!heap.is_empty())
1131 {
1132 int curr = heap.extract_min();
1133 EXPECT_LE(prev, curr);
1134 prev = curr;
1135 }
1136}
1137
1138// =============================================================================
1139// Heap Property Verification Tests
1140// =============================================================================
1141
1142// Helper to verify heap property
1143template <typename T, typename Compare>
1145{
1146 if (heap.is_empty())
1147 return true;
1148
1149 std::vector<T> extracted;
1150 while (!heap.is_empty())
1151 extracted.push_back(heap.extract_min());
1152
1153 // Verify sorted (for min-heap)
1154 for (size_t i = 1; i < extracted.size(); ++i)
1155 {
1156 if (extracted[i] < extracted[i - 1])
1157 return false;
1158 }
1159
1160 return true;
1161}
1162
1164{
1166 std::random_device rd;
1167 std::mt19937 gen(42);
1168 std::uniform_int_distribution<> dis(-10000, 10000);
1169
1170 for (int i = 0; i < 1000; ++i)
1171 heap.insert(dis(gen));
1172
1174}
1175
1177{
1179 std::vector<Fibonacci_Heap<int>::Node *> nodes;
1180
1181 for (int i = 0; i < 100; ++i)
1182 nodes.push_back(heap.insert(i + 100));
1183
1184 // Extract to build structure
1185 for (int i = 0; i < 20; ++i)
1186 heap.extract_min();
1187
1188 // Decrease some keys
1189 for (size_t i = 30; i < 50; ++i)
1190 heap.decrease_key(nodes[i], static_cast<int>(i - 30));
1191
1193}
1194
1196{
1198 std::random_device rd;
1199 std::mt19937 gen(42);
1200 std::uniform_int_distribution<> dis(1, 1000);
1201
1202 for (int i = 0; i < 500; ++i)
1203 {
1204 h1.insert(dis(gen));
1205 h2.insert(dis(gen));
1206 }
1207
1208 h1.merge(h2);
1209
1211}
1212
1213// =============================================================================
1214// Memory and Performance Tests
1215// =============================================================================
1216
1218{
1219 // This test mainly checks for memory leaks (run with valgrind/asan)
1220 for (int trial = 0; trial < 10; ++trial)
1221 {
1223 for (int i = 0; i < 1000; ++i)
1224 heap.insert(i);
1225 // Destructor should free all nodes
1226 }
1227}
1228
1230{
1231 // Run with valgrind/asan to check for leaks
1233 for (int i = 0; i < 1000; ++i)
1234 heap.insert(i);
1235
1236 heap.clear();
1237
1238 for (int i = 0; i < 1000; ++i)
1239 heap.insert(i + 1000);
1240}
1241
1242// Performance test (disabled by default due to time)
1244{
1245 constexpr int N = 1000000;
1246
1247 auto start = std::chrono::high_resolution_clock::now();
1248
1250 for (int i = N; i >= 1; --i)
1251 (void)heap.insert(i);
1252
1253 auto after_insert = std::chrono::high_resolution_clock::now();
1254
1255 while (!heap.is_empty())
1256 heap.extract_min();
1257
1258 auto after_extract = std::chrono::high_resolution_clock::now();
1259
1260 auto insert_time = std::chrono::duration_cast<std::chrono::milliseconds>(
1261 after_insert - start).count();
1262 auto extract_time = std::chrono::duration_cast<std::chrono::milliseconds>(
1263 after_extract - after_insert).count();
1264
1265 std::cout << "Insert " << N << " elements: " << insert_time << " ms\n";
1266 std::cout << "Extract " << N << " elements: " << extract_time << " ms\n";
1267}
1268
1269// =============================================================================
1270// Dijkstra-like Usage Pattern Test
1271// =============================================================================
1272
1274{
1275 // Simulate Dijkstra's algorithm usage pattern
1276 struct DistNode
1277 {
1278 int vertex;
1279 int distance;
1280
1281 bool operator<(const DistNode & other) const
1282 {
1283 return distance < other.distance;
1284 }
1285 };
1286
1288 std::vector<Fibonacci_Heap<DistNode>::Node *> handles(100, nullptr);
1289
1290 // Initialize all vertices with infinite distance except source
1291 for (int v = 0; v < 100; ++v)
1292 {
1293 int dist = (v == 0) ? 0 : std::numeric_limits<int>::max();
1294 handles[v] = pq.insert({v, dist});
1295 }
1296
1297 // Simulate relaxation
1298 std::random_device rd;
1299 std::mt19937 gen(42);
1300 std::uniform_int_distribution<> dist_gen(1, 100);
1301
1302 while (!pq.is_empty())
1303 {
1304 DistNode u = pq.extract_min();
1305
1306 // Mark as processed BEFORE accessing other handles
1307 // (the extracted node's handle is now invalid)
1308 handles[u.vertex] = nullptr;
1309
1310 // Simulate relaxing neighbors
1311 for (int i = 0; i < 3; ++i)
1312 {
1313 int v = dist_gen(gen) % 100;
1314 // Only access handles that haven't been extracted yet
1315 if (handles[v] != nullptr && handles[v]->data.distance > u.distance + 10)
1316 {
1317 // Decrease key to simulate edge relaxation
1318 pq.decrease_key(handles[v], {v, u.distance + 10});
1319 }
1320 }
1321 }
1322}
1323
1324// =============================================================================
1325// Comparator Tests
1326// =============================================================================
1327
1329{
1331 auto cmp = heap.key_comp();
1332
1333 EXPECT_TRUE(cmp(1, 2));
1334 EXPECT_FALSE(cmp(2, 1));
1335 EXPECT_FALSE(cmp(1, 1));
1336}
1337
1339{
1340 auto cmp = [](int a, int b) { return a > b; }; // Max heap
1341 Fibonacci_Heap<int, decltype(cmp)> heap(cmp);
1342
1343 (void)heap.insert(10);
1344 (void)heap.insert(30);
1345 (void)heap.insert(20);
1346
1347 EXPECT_EQ(heap.extract_min(), 30);
1348 EXPECT_EQ(heap.extract_min(), 20);
1349 EXPECT_EQ(heap.extract_min(), 10);
1350}
1351
1352// =============================================================================
1353// Additional Edge Case Tests
1354// =============================================================================
1355
1357{
1359 auto node = heap.insert(50);
1360 heap.insert(60);
1361 heap.insert(70);
1362
1363 // Decrease the minimum (root) node - should just update data
1364 heap.decrease_key(node, 10);
1365
1366 EXPECT_EQ(heap.get_min(), 10);
1367 EXPECT_EQ(heap.extract_min(), 10);
1368 EXPECT_EQ(heap.extract_min(), 60);
1369 EXPECT_EQ(heap.extract_min(), 70);
1370}
1371
1373{
1375
1376 // Insert values that will create parent-child relationships after consolidate
1377 for (int i = 1; i <= 10; ++i)
1378 heap.insert(i * 10);
1379
1380 // Extract to force consolidation
1381 heap.extract_min(); // Remove 10
1382 heap.extract_min(); // Remove 20
1383
1384 // Insert a large value and then decrease it
1385 auto node = heap.insert(1000);
1386 heap.decrease_key(node, 5); // Now smaller than any remaining
1387
1388 EXPECT_EQ(heap.get_min(), 5);
1389
1390 // Verify heap property is maintained
1391 int prev = heap.extract_min();
1392 while (!heap.is_empty())
1393 {
1394 int curr = heap.extract_min();
1395 EXPECT_LE(prev, curr);
1396 prev = curr;
1397 }
1398}
1399
1401{
1403 std::vector<Fibonacci_Heap<int>::Node *> nodes;
1404
1405 // Insert 15 elements to create trees with multiple children
1406 for (int i = 0; i < 15; ++i)
1407 nodes.push_back(heap.insert(i + 1));
1408
1409 // Extract several times to build tree structure with children
1410 for (int i = 0; i < 4; ++i)
1411 heap.extract_min();
1412
1413 // Delete a node that likely has children (after consolidation)
1414 // Node with value 8 should still be in the heap
1415 heap.delete_node(nodes[7]); // Delete node with original value 8
1416
1417 // Verify heap property and correct count
1418 EXPECT_EQ(heap.size(), 10u); // 15 - 4 extracted - 1 deleted
1419
1420 int prev = heap.extract_min();
1421 while (!heap.is_empty())
1422 {
1423 int curr = heap.extract_min();
1424 EXPECT_LE(prev, curr);
1425 prev = curr;
1426 }
1427}
1428
1430{
1432 heap.insert(10);
1433 heap.insert(20);
1434
1435 heap.merge(heap); // Self-merge should be no-op
1436
1437 EXPECT_EQ(heap.size(), 2u);
1438 EXPECT_EQ(heap.get_min(), 10);
1439}
1440
1442{
1444
1445 // Create structure with parent-child relationships
1446 for (int i = 1; i <= 10; ++i)
1447 heap.insert(i * 10);
1448
1449 // Extract to consolidate
1450 heap.extract_min();
1451
1452 // Insert and update to same value
1453 auto node = heap.insert(500);
1454 auto result = heap.update_key(node, 500);
1455
1456 EXPECT_EQ(result, node);
1457 EXPECT_EQ(result->data, 500);
1458}
1459
1461{
1463
1464 auto node = heap.insert(100);
1465 heap.insert(200);
1466 heap.insert(300);
1467
1468 // Multiple consecutive decrease keys on same node
1469 heap.decrease_key(node, 90);
1470 EXPECT_EQ(heap.get_min(), 90);
1471
1472 heap.decrease_key(node, 50);
1473 EXPECT_EQ(heap.get_min(), 50);
1474
1475 heap.decrease_key(node, 10);
1476 EXPECT_EQ(heap.get_min(), 10);
1477
1478 // Verify extraction order
1479 EXPECT_EQ(heap.extract_min(), 10);
1480 EXPECT_EQ(heap.extract_min(), 200);
1481 EXPECT_EQ(heap.extract_min(), 300);
1482}
1483
1485{
1487
1488 // emplace with single arg should work (goes through insert path)
1489 auto node = heap.emplace(42);
1490
1491 EXPECT_EQ(node->data, 42);
1492 EXPECT_EQ(heap.get_min(), 42);
1493}
1494
1496{
1498
1499 // Insert enough elements to create high-degree trees
1500 // Fibonacci heap can have trees of degree up to log_phi(n)
1501 constexpr int N = 10000;
1502 for (int i = N; i >= 1; --i)
1503 heap.insert(i);
1504
1505 // Extract half to create complex tree structure
1506 for (int i = 0; i < N / 2; ++i)
1507 {
1508 int val = heap.extract_min();
1509 EXPECT_EQ(val, i + 1);
1510 }
1511
1512 // Verify remaining half
1513 for (int i = N / 2 + 1; i <= N; ++i)
1514 {
1515 int val = heap.extract_min();
1516 EXPECT_EQ(val, i);
1517 }
1518
1519 EXPECT_TRUE(heap.is_empty());
1520}
1521
1523{
1525
1526 h1.swap(h2);
1527
1528 EXPECT_TRUE(h1.is_empty());
1529 EXPECT_TRUE(h2.is_empty());
1530}
1531
1533{
1535 heap.insert(1);
1536 heap.insert(2);
1537 heap.insert(3);
1538
1539#pragma GCC diagnostic push
1540#pragma GCC diagnostic ignored "-Wself-move"
1541 heap = std::move(heap);
1542#pragma GCC diagnostic pop
1543
1544 // After self-move, the heap should still be valid (either empty or same)
1545 // This is implementation-defined, but should not crash
1546}
1547
1549{
1551 auto n1 = heap.insert(10);
1552 auto n2 = heap.insert(20);
1553
1554 heap.delete_node(n1);
1555 EXPECT_EQ(heap.size(), 1u);
1556 EXPECT_EQ(heap.get_min(), 20);
1557
1558 heap.delete_node(n2);
1559 EXPECT_TRUE(heap.is_empty());
1560}
1561
1562// =============================================================================
1563// Regression Tests
1564// =============================================================================
1565
1566// Test that delete_node properly handles the case where the deleted node
1567// is alone in the root list but has children
1569{
1571
1572 // Build a specific structure
1573 heap.insert(1);
1574 heap.insert(2);
1575 heap.insert(3);
1576 heap.insert(4);
1577
1578 // Extract to consolidate into a single tree
1579 EXPECT_EQ(heap.extract_min(), 1);
1580 EXPECT_EQ(heap.extract_min(), 2);
1581
1582 // Now we have 3 and 4, likely in a parent-child relationship
1583 // Delete the root (3)
1584 auto root = heap.get_min_node();
1585 heap.delete_node(root);
1586
1587 // Should have only 4 left
1588 EXPECT_EQ(heap.size(), 1u);
1589 EXPECT_EQ(heap.get_min(), 4);
1590}
1591
1592// Test cascading cuts trigger properly
1594{
1596 std::vector<Fibonacci_Heap<int>::Node *> nodes;
1597
1598 // Create a deep tree by inserting many elements
1599 for (int i = 1; i <= 100; ++i)
1600 nodes.push_back(heap.insert(i * 100));
1601
1602 // Extract several to build tree structure
1603 for (int i = 0; i < 30; ++i)
1604 heap.extract_min();
1605
1606 // Now decrease keys to trigger cascading cuts
1607 // Decrease non-extracted nodes in sequence
1608 int key = 1;
1609 for (size_t i = 50; i < 70; ++i)
1610 {
1611 if (nodes[i]->data > key)
1612 {
1613 heap.decrease_key(nodes[i], key);
1614 ++key;
1615 }
1616 }
1617
1618 // Verify heap property is maintained
1619 int prev = heap.extract_min();
1620 while (!heap.is_empty())
1621 {
1622 int curr = heap.extract_min();
1623 EXPECT_LE(prev, curr);
1624 prev = curr;
1625 }
1626}
1627
1628int main(int argc, char **argv)
1629{
1630 ::testing::InitGoogleTest(&argc, argv);
1631 return RUN_ALL_TESTS();
1632}
bool operator<(const Time &l, const Time &r)
Definition ah-time.H:142
int main()
long double h
Definition btreepic.C:154
Implementation of a Fibonacci Heap priority queue.
void swap(Fibonacci_Heap &other) noexcept
Swaps contents with another heap.
const T & get_min() const
Returns the minimum element without removing it.
Node * get_min_node() const noexcept
Returns a pointer to the minimum node.
Compare key_comp() const
Returns the comparison functor.
void clear() noexcept(std::is_nothrow_destructible_v< T >)
Removes all elements from the heap.
Node * insert(const T &val)
Inserts a new element (copy).
void merge(Fibonacci_Heap &other)
Merges another heap into this one.
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.
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).
void decrease_key(Node *x, const T &k)
Decreases the key of a node.
bool is_empty() const noexcept
Checks if the heap is empty.
Represents a point with rectangular coordinates in a 2D plane.
Definition point.H:221
Minimal std::expected-style result type for C++20.
Fibonacci_Heap< int > heap
std::vector< Fibonacci_Heap< int >::Node * > nodes
#define TEST(name)
#define N
Definition fib.C:294
bool verify_heap_property(Fibonacci_Heap< T, Compare > &heap)
TEST_F(FibonacciHeapTest, InsertSingleElement)
__gmp_expr< T, __gmp_binary_expr< __gmp_expr< T, U >, unsigned long int, __gmp_root_function > > root(const __gmp_expr< T, U > &expr, unsigned long int l)
Definition gmpfrxx.h:4071
int cmp(const __gmp_expr< T, U > &expr1, const __gmp_expr< V, W > &expr2)
Definition gmpfrxx.h:4129
DynArray< Graph::Node * > nodes
Definition graphpic.C:406
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
T & swap(T &t1, T &t2)
Generic swap using object's swap method.
Definition ahTypes.H:121
size_t size(Node *root) noexcept
Itor3 merge(Itor1 source1Beg, Itor1 source1End, Itor2 source2Beg, Itor2 source2End, Itor3 destBeg)
Merge two sorted ranges.
Definition ahAlgo.H:1410
Represents a node in the Fibonacci Heap.
bool operator<(const Point &other) const
double distance() const
static long counter
Definition test-splice.C:40
Fibonacci Heap implementation.