authorgravatar for saurabh.m@proton.meSaurabh Mishra <saurabh.m@proton.me> 2026-02-18 13:24:03-08:00
committergravatar for saurabh.m@proton.meSaurabh Mishra <saurabh.m@proton.me> 2026-02-18 13:24:03-08:00
log5140455264347f8bf869edae71faa8848e92dabd
tree73d652fc11b1db24154ac5246f03beb22bb95dd8
parent293710c1cd3160787e882113014c022ce665d16d

min heap is formed with less than comparison


1 files changed, 59 insertions(+), 56 deletions(-)

lib/std/priority_dequeue.zig+59-56
...@@ -449,17 +449,20 @@ pub fn PriorityDequeue(comptime T: type, comptime Context: type, comptime compar...@@ -449,17 +449,20 @@ pub fn PriorityDequeue(comptime T: type, comptime Context: type, comptime compar
449 };449 };
450}450}
451451
452/// If a min heap is constructed from slice `{5, 8, 2, 9, 7, 1, 4, 4}` using this
453/// method, then the elements will be in order: {1, 2, 4, 4, 5, 7, 8, 9}
452fn lessThanComparison(context: void, a: u32, b: u32) Order {454fn lessThanComparison(context: void, a: u32, b: u32) Order {
453 _ = context;455 _ = context;
454 return std.math.order(a, b);456 return std.math.order(a, b);
455}457}
456458
457const PDQ = PriorityDequeue(u32, void, lessThanComparison);459/// Elements with lower priority will be removed first
460const MinHeap = PriorityDequeue(u32, void, lessThanComparison);
458461
459test "push and pop min" {462test "push and pop min in min heap" {
460 const gpa = std.testing.allocator;463 const gpa = std.testing.allocator;
461464
462 var queue: PDQ = .empty;465 var queue: MinHeap = .empty;
463 defer queue.deinit(gpa);466 defer queue.deinit(gpa);
464467
465 try queue.push(gpa, 54);468 try queue.push(gpa, 54);
...@@ -506,10 +509,10 @@ test "push and pop min structs" {...@@ -506,10 +509,10 @@ test "push and pop min structs" {
506 try expectEqual(@as(u32, 54), queue.popMin().?.size);509 try expectEqual(@as(u32, 54), queue.popMin().?.size);
507}510}
508511
509test "push and pop max" {512test "push and pop max in min heap" {
510 const gpa = std.testing.allocator;513 const gpa = std.testing.allocator;
511514
512 var queue: PDQ = .empty;515 var queue: MinHeap = .empty;
513 defer queue.deinit(gpa);516 defer queue.deinit(gpa);
514517
515 try queue.push(gpa, 54);518 try queue.push(gpa, 54);
...@@ -527,10 +530,10 @@ test "push and pop max" {...@@ -527,10 +530,10 @@ test "push and pop max" {
527 try expectEqual(@as(u32, 7), queue.popMax());530 try expectEqual(@as(u32, 7), queue.popMax());
528}531}
529532
530test "push and pop same min" {533test "push and pop same min in min heap" {
531 const gpa = std.testing.allocator;534 const gpa = std.testing.allocator;
532535
533 var queue: PDQ = .empty;536 var queue: MinHeap = .empty;
534 defer queue.deinit(gpa);537 defer queue.deinit(gpa);
535538
536 try queue.push(gpa, 1);539 try queue.push(gpa, 1);
...@@ -548,10 +551,10 @@ test "push and pop same min" {...@@ -548,10 +551,10 @@ test "push and pop same min" {
548 try expectEqual(@as(u32, 2), queue.popMin());551 try expectEqual(@as(u32, 2), queue.popMin());
549}552}
550553
551test "push and pop same max" {554test "push and pop same max in min heap" {
552 const gpa = std.testing.allocator;555 const gpa = std.testing.allocator;
553556
554 var queue: PDQ = .empty;557 var queue: MinHeap = .empty;
555 defer queue.deinit(gpa);558 defer queue.deinit(gpa);
556559
557 try queue.push(gpa, 1);560 try queue.push(gpa, 1);
...@@ -569,20 +572,20 @@ test "push and pop same max" {...@@ -569,20 +572,20 @@ test "push and pop same max" {
569 try expectEqual(@as(u32, 1), queue.popMax());572 try expectEqual(@as(u32, 1), queue.popMax());
570}573}
571574
572test "popOrNull empty" {575test "pop empty in min heap" {
573 const gpa = std.testing.allocator;576 const gpa = std.testing.allocator;
574577
575 var queue: PDQ = .empty;578 var queue: MinHeap = .empty;
576 defer queue.deinit(gpa);579 defer queue.deinit(gpa);
577580
578 try expect(queue.popMin() == null);581 try expect(queue.popMin() == null);
579 try expect(queue.popMax() == null);582 try expect(queue.popMax() == null);
580}583}
581584
582test "edge case 3 elements" {585test "edge case 3 elements popMin in min heap" {
583 const gpa = std.testing.allocator;586 const gpa = std.testing.allocator;
584587
585 var queue: PDQ = .empty;588 var queue: MinHeap = .empty;
586 defer queue.deinit(gpa);589 defer queue.deinit(gpa);
587590
588 try queue.push(gpa, 9);591 try queue.push(gpa, 9);
...@@ -594,10 +597,10 @@ test "edge case 3 elements" {...@@ -594,10 +597,10 @@ test "edge case 3 elements" {
594 try expectEqual(@as(u32, 9), queue.popMin());597 try expectEqual(@as(u32, 9), queue.popMin());
595}598}
596599
597test "edge case 3 elements max" {600test "edge case 3 elements popmax in min heap" {
598 const gpa = std.testing.allocator;601 const gpa = std.testing.allocator;
599602
600 var queue: PDQ = .empty;603 var queue: MinHeap = .empty;
601 defer queue.deinit(gpa);604 defer queue.deinit(gpa);
602605
603 try queue.push(gpa, 9);606 try queue.push(gpa, 9);
...@@ -609,10 +612,10 @@ test "edge case 3 elements max" {...@@ -609,10 +612,10 @@ test "edge case 3 elements max" {
609 try expectEqual(@as(u32, 2), queue.popMax());612 try expectEqual(@as(u32, 2), queue.popMax());
610}613}
611614
612test "peekMin" {615test "peekMin in min heap" {
613 const gpa = std.testing.allocator;616 const gpa = std.testing.allocator;
614617
615 var queue: PDQ = .empty;618 var queue: MinHeap = .empty;
616 defer queue.deinit(gpa);619 defer queue.deinit(gpa);
617620
618 try expect(queue.peekMin() == null);621 try expect(queue.peekMin() == null);
...@@ -625,10 +628,10 @@ test "peekMin" {...@@ -625,10 +628,10 @@ test "peekMin" {
625 try expect(queue.peekMin().? == 2);628 try expect(queue.peekMin().? == 2);
626}629}
627630
628test "peekMax" {631test "peekMax in min heap" {
629 const gpa = std.testing.allocator;632 const gpa = std.testing.allocator;
630633
631 var queue: PDQ = .empty;634 var queue: MinHeap = .empty;
632 defer queue.deinit(gpa);635 defer queue.deinit(gpa);
633636
634 try expect(queue.peekMin() == null);637 try expect(queue.peekMin() == null);
...@@ -641,10 +644,10 @@ test "peekMax" {...@@ -641,10 +644,10 @@ test "peekMax" {
641 try expect(queue.peekMax().? == 9);644 try expect(queue.peekMax().? == 9);
642}645}
643646
644test "sift up with odd indices, popMin" {647test "sift up with odd indices and popMin in min heap" {
645 const gpa = std.testing.allocator;648 const gpa = std.testing.allocator;
646649
647 var queue: PDQ = .empty;650 var queue: MinHeap = .empty;
648 defer queue.deinit(gpa);651 defer queue.deinit(gpa);
649652
650 const items = [_]u32{ 15, 7, 21, 14, 13, 22, 12, 6, 7, 25, 5, 24, 11, 16, 15, 24, 2, 1 };653 const items = [_]u32{ 15, 7, 21, 14, 13, 22, 12, 6, 7, 25, 5, 24, 11, 16, 15, 24, 2, 1 };
...@@ -658,10 +661,10 @@ test "sift up with odd indices, popMin" {...@@ -658,10 +661,10 @@ test "sift up with odd indices, popMin" {
658 }661 }
659}662}
660663
661test "sift up with odd indices, popMax" {664test "sift up with odd indices and popMax in min heap" {
662 const gpa = std.testing.allocator;665 const gpa = std.testing.allocator;
663666
664 var queue: PDQ = .empty;667 var queue: MinHeap = .empty;
665 defer queue.deinit(gpa);668 defer queue.deinit(gpa);
666669
667 const items = [_]u32{ 15, 7, 21, 14, 13, 22, 12, 6, 7, 25, 5, 24, 11, 16, 15, 24, 2, 1 };670 const items = [_]u32{ 15, 7, 21, 14, 13, 22, 12, 6, 7, 25, 5, 24, 11, 16, 15, 24, 2, 1 };
...@@ -675,10 +678,10 @@ test "sift up with odd indices, popMax" {...@@ -675,10 +678,10 @@ test "sift up with odd indices, popMax" {
675 }678 }
676}679}
677680
678test "pushSlice min" {681test "pushSlice in min heap and popMin" {
679 const gpa = std.testing.allocator;682 const gpa = std.testing.allocator;
680683
681 var queue: PDQ = .empty;684 var queue: MinHeap = .empty;
682 defer queue.deinit(gpa);685 defer queue.deinit(gpa);
683686
684 const items = [_]u32{ 15, 7, 21, 14, 13, 22, 12, 6, 7, 25, 5, 24, 11, 16, 15, 24, 2, 1 };687 const items = [_]u32{ 15, 7, 21, 14, 13, 22, 12, 6, 7, 25, 5, 24, 11, 16, 15, 24, 2, 1 };
...@@ -690,10 +693,10 @@ test "pushSlice min" {...@@ -690,10 +693,10 @@ test "pushSlice min" {
690 }693 }
691}694}
692695
693test "pushSlice max" {696test "pushSlice in min heap and popMax" {
694 const gpa = std.testing.allocator;697 const gpa = std.testing.allocator;
695698
696 var queue: PDQ = .empty;699 var queue: MinHeap = .empty;
697 defer queue.deinit(gpa);700 defer queue.deinit(gpa);
698701
699 const items = [_]u32{ 15, 7, 21, 14, 13, 22, 12, 6, 7, 25, 5, 24, 11, 16, 15, 24, 2, 1 };702 const items = [_]u32{ 15, 7, 21, 14, 13, 22, 12, 6, 7, 25, 5, 24, 11, 16, 15, 24, 2, 1 };
...@@ -705,26 +708,26 @@ test "pushSlice max" {...@@ -705,26 +708,26 @@ test "pushSlice max" {
705 }708 }
706}709}
707710
708test "fromOwnedSlice trivial case 0" {711test "fromOwnedSlice trivial case 0 min heap" {
709 const gpa = std.testing.allocator;712 const gpa = std.testing.allocator;
710713
711 const items = [0]u32{};714 const items = [0]u32{};
712 const queue_items = try gpa.dupe(u32, &items);715 const queue_items = try gpa.dupe(u32, &items);
713716
714 var queue = PDQ.fromOwnedSlice(queue_items[0..], {});717 var queue: MinHeap = .fromOwnedSlice(queue_items[0..], {});
715 defer queue.deinit(gpa);718 defer queue.deinit(gpa);
716719
717 try expectEqual(@as(usize, 0), queue.len);720 try expectEqual(@as(usize, 0), queue.len);
718 try expect(queue.popMin() == null);721 try expect(queue.popMin() == null);
719}722}
720723
721test "fromOwnedSlice trivial case 1" {724test "fromOwnedSlice trivial case 1 min heap" {
722 const gpa = std.testing.allocator;725 const gpa = std.testing.allocator;
723726
724 const items = [1]u32{1};727 const items = [1]u32{1};
725 const queue_items = try gpa.dupe(u32, &items);728 const queue_items = try gpa.dupe(u32, &items);
726729
727 var queue = PDQ.fromOwnedSlice(queue_items[0..], {});730 var queue: MinHeap = .fromOwnedSlice(queue_items[0..], {});
728 defer queue.deinit(gpa);731 defer queue.deinit(gpa);
729732
730 try expectEqual(@as(usize, 1), queue.len);733 try expectEqual(@as(usize, 1), queue.len);
...@@ -732,13 +735,13 @@ test "fromOwnedSlice trivial case 1" {...@@ -732,13 +735,13 @@ test "fromOwnedSlice trivial case 1" {
732 try expect(queue.popMin() == null);735 try expect(queue.popMin() == null);
733}736}
734737
735test "fromOwnedSlice" {738test "fromOwnedSlice min heap" {
736 const gpa = std.testing.allocator;739 const gpa = std.testing.allocator;
737740
738 const items = [_]u32{ 15, 7, 21, 14, 13, 22, 12, 6, 7, 25, 5, 24, 11, 16, 15, 24, 2, 1 };741 const items = [_]u32{ 15, 7, 21, 14, 13, 22, 12, 6, 7, 25, 5, 24, 11, 16, 15, 24, 2, 1 };
739 const queue_items = try gpa.dupe(u32, items[0..]);742 const queue_items = try gpa.dupe(u32, items[0..]);
740743
741 var queue = PDQ.fromOwnedSlice(queue_items[0..], {});744 var queue: MinHeap = .fromOwnedSlice(queue_items[0..], {});
742 defer queue.deinit(gpa);745 defer queue.deinit(gpa);
743746
744 const sorted_items = [_]u32{ 1, 2, 5, 6, 7, 7, 11, 12, 13, 14, 15, 15, 16, 21, 22, 24, 24, 25 };747 const sorted_items = [_]u32{ 1, 2, 5, 6, 7, 7, 11, 12, 13, 14, 15, 15, 16, 21, 22, 24, 24, 25 };
...@@ -747,10 +750,10 @@ test "fromOwnedSlice" {...@@ -747,10 +750,10 @@ test "fromOwnedSlice" {
747 }750 }
748}751}
749752
750test "update min queue" {753test "update and popMin in min heap" {
751 const gpa = std.testing.allocator;754 const gpa = std.testing.allocator;
752755
753 var queue: PDQ = .empty;756 var queue: MinHeap = .empty;
754 defer queue.deinit(gpa);757 defer queue.deinit(gpa);
755758
756 try queue.push(gpa, 55);759 try queue.push(gpa, 55);
...@@ -764,10 +767,10 @@ test "update min queue" {...@@ -764,10 +767,10 @@ test "update min queue" {
764 try expectEqual(@as(u32, 5), queue.popMin());767 try expectEqual(@as(u32, 5), queue.popMin());
765}768}
766769
767test "update same min queue" {770test "update same element and popMin in min heap" {
768 const gpa = std.testing.allocator;771 const gpa = std.testing.allocator;
769772
770 var queue: PDQ = .empty;773 var queue: MinHeap = .empty;
771 defer queue.deinit(gpa);774 defer queue.deinit(gpa);
772775
773 try queue.push(gpa, 1);776 try queue.push(gpa, 1);
...@@ -782,10 +785,10 @@ test "update same min queue" {...@@ -782,10 +785,10 @@ test "update same min queue" {
782 try expectEqual(@as(u32, 5), queue.popMin());785 try expectEqual(@as(u32, 5), queue.popMin());
783}786}
784787
785test "update max queue" {788test "update and popMax in min heap" {
786 const gpa = std.testing.allocator;789 const gpa = std.testing.allocator;
787790
788 var queue: PDQ = .empty;791 var queue: MinHeap = .empty;
789 defer queue.deinit(gpa);792 defer queue.deinit(gpa);
790793
791 try queue.push(gpa, 55);794 try queue.push(gpa, 55);
...@@ -800,10 +803,10 @@ test "update max queue" {...@@ -800,10 +803,10 @@ test "update max queue" {
800 try expectEqual(@as(u32, 1), queue.popMax());803 try expectEqual(@as(u32, 1), queue.popMax());
801}804}
802805
803test "update same max queue" {806test "update same element and popMax in min heap" {
804 const gpa = std.testing.allocator;807 const gpa = std.testing.allocator;
805808
806 var queue: PDQ = .empty;809 var queue: MinHeap = .empty;
807 defer queue.deinit(gpa);810 defer queue.deinit(gpa);
808811
809 try queue.push(gpa, 1);812 try queue.push(gpa, 1);
...@@ -818,10 +821,10 @@ test "update same max queue" {...@@ -818,10 +821,10 @@ test "update same max queue" {
818 try expectEqual(@as(u32, 1), queue.popMax());821 try expectEqual(@as(u32, 1), queue.popMax());
819}822}
820823
821test "update after pop" {824test "update after pop in min heap" {
822 const gpa = std.testing.allocator;825 const gpa = std.testing.allocator;
823826
824 var queue: PDQ = .empty;827 var queue: MinHeap = .empty;
825 defer queue.deinit(gpa);828 defer queue.deinit(gpa);
826829
827 try queue.push(gpa, 1);830 try queue.push(gpa, 1);
...@@ -829,10 +832,10 @@ test "update after pop" {...@@ -829,10 +832,10 @@ test "update after pop" {
829 try expectError(error.ElementNotFound, queue.update(1, 1));832 try expectError(error.ElementNotFound, queue.update(1, 1));
830}833}
831834
832test "iterator" {835test "min heap iterator" {
833 const gpa = std.testing.allocator;836 const gpa = std.testing.allocator;
834837
835 var queue: PDQ = .empty;838 var queue: MinHeap = .empty;
836 var map = std.AutoHashMap(u32, void).init(testing.allocator);839 var map = std.AutoHashMap(u32, void).init(testing.allocator);
837 defer {840 defer {
838 queue.deinit(gpa);841 queue.deinit(gpa);
...@@ -853,10 +856,10 @@ test "iterator" {...@@ -853,10 +856,10 @@ test "iterator" {
853 try expectEqual(@as(usize, 0), map.count());856 try expectEqual(@as(usize, 0), map.count());
854}857}
855858
856test "pop at index" {859test "pop at index in min heap" {
857 const gpa = std.testing.allocator;860 const gpa = std.testing.allocator;
858861
859 var queue: PDQ = .empty;862 var queue: MinHeap = .empty;
860 defer queue.deinit(gpa);863 defer queue.deinit(gpa);
861864
862 try queue.push(gpa, 3);865 try queue.push(gpa, 3);
...@@ -878,10 +881,10 @@ test "pop at index" {...@@ -878,10 +881,10 @@ test "pop at index" {
878 try expectEqual(queue.popMin(), null);881 try expectEqual(queue.popMin(), null);
879}882}
880883
881test "iterator while empty" {884test "min heap iterator while empty" {
882 const gpa = std.testing.allocator;885 const gpa = std.testing.allocator;
883886
884 var queue: PDQ = .empty;887 var queue: MinHeap = .empty;
885 defer queue.deinit(gpa);888 defer queue.deinit(gpa);
886889
887 var it = queue.iterator();890 var it = queue.iterator();
...@@ -889,10 +892,10 @@ test "iterator while empty" {...@@ -889,10 +892,10 @@ test "iterator while empty" {
889 try expectEqual(it.next(), null);892 try expectEqual(it.next(), null);
890}893}
891894
892test "shrinkAndFree" {895test "min heap shrinkAndFree" {
893 const gpa = std.testing.allocator;896 const gpa = std.testing.allocator;
894897
895 var queue: PDQ = .empty;898 var queue: MinHeap = .empty;
896 defer queue.deinit(gpa);899 defer queue.deinit(gpa);
897900
898 try queue.ensureTotalCapacity(gpa, 4);901 try queue.ensureTotalCapacity(gpa, 4);
...@@ -932,7 +935,7 @@ fn fuzzTestMin(rng: std.Random, comptime queue_size: usize) !void {...@@ -932,7 +935,7 @@ fn fuzzTestMin(rng: std.Random, comptime queue_size: usize) !void {
932935
933 const items = try generateRandomSlice(gpa, rng, queue_size);936 const items = try generateRandomSlice(gpa, rng, queue_size);
934937
935 var queue = PDQ.fromOwnedSlice(items, {});938 var queue: MinHeap = .fromOwnedSlice(items, {});
936 defer queue.deinit(gpa);939 defer queue.deinit(gpa);
937940
938 var last_removed: ?u32 = null;941 var last_removed: ?u32 = null;
...@@ -962,7 +965,7 @@ fn fuzzTestMax(rng: std.Random, queue_size: usize) !void {...@@ -962,7 +965,7 @@ fn fuzzTestMax(rng: std.Random, queue_size: usize) !void {
962965
963 const items = try generateRandomSlice(gpa, rng, queue_size);966 const items = try generateRandomSlice(gpa, rng, queue_size);
964967
965 var queue = PDQ.fromOwnedSlice(items, {});968 var queue: MinHeap = .fromOwnedSlice(items, {});
966 defer queue.deinit(gpa);969 defer queue.deinit(gpa);
967970
968 var last_removed: ?u32 = null;971 var last_removed: ?u32 = null;
...@@ -992,7 +995,7 @@ fn fuzzTestMinMax(rng: std.Random, queue_size: usize) !void {...@@ -992,7 +995,7 @@ fn fuzzTestMinMax(rng: std.Random, queue_size: usize) !void {
992995
993 const items = try generateRandomSlice(gpa, rng, queue_size);996 const items = try generateRandomSlice(gpa, rng, queue_size);
994997
995 var queue = PDQ.fromOwnedSlice(items, {});998 var queue: MinHeap = .fromOwnedSlice(items, {});
996 defer queue.deinit(gpa);999 defer queue.deinit(gpa);
9971000
998 var last_min: ?u32 = null;1001 var last_min: ?u32 = null;
...@@ -1032,14 +1035,14 @@ fn contextLessThanComparison(context: []const u32, a: usize, b: usize) Order {...@@ -1032,14 +1035,14 @@ fn contextLessThanComparison(context: []const u32, a: usize, b: usize) Order {
1032 return std.math.order(context[a], context[b]);1035 return std.math.order(context[a], context[b]);
1033}1036}
10341037
1035const CPDQ = PriorityDequeue(usize, []const u32, contextLessThanComparison);1038const MinHeapWithContext = PriorityDequeue(usize, []const u32, contextLessThanComparison);
10361039
1037test "push and pop" {1040test "push and pop" {
1038 const gpa = std.testing.allocator;1041 const gpa = std.testing.allocator;
10391042
1040 const context = [_]u32{ 5, 3, 4, 2, 2, 8, 0 };1043 const context = [_]u32{ 5, 3, 4, 2, 2, 8, 0 };
10411044
1042 var queue: CPDQ = .initContext(context[0..]);1045 var queue: MinHeapWithContext = .initContext(context[0..]);
1043 defer queue.deinit(gpa);1046 defer queue.deinit(gpa);
10441047
1045 try queue.push(gpa, 0);1048 try queue.push(gpa, 0);