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