min-heap

Crates.iomin-heap
lib.rsmin-heap
version1.0.0
created_at2025-05-04 17:53:57.859053+00
updated_at2025-05-04 17:53:57.859053+00
descriptionA Min Priority Queue implemented as a Thin Wrapper around BinaryHeap from the Standard Library
homepage
repositoryhttps://github.com/GBathie/min_heap
max_upload_size
id1659830
size55,153
Gabriel Bathie (GBathie)

documentation

README

MinHeap

MinHeap: A Min Priority Queue implemented as a Thin Wrapper around [BinaryHeap<Reverse<T>>] from the standard library.


Quickstart

Add min_heap as a dependency: run cargo add min_heap, or add the following to your Cargo.toml file.

[dependencies]
min_heap = "1.0"

min_heap::MinHeap mirrors the API of std::collections::BinaryHeap; here is an overview of what you can do with it.

use min_heap::MinHeap;
// Type inference lets us omit an explicit type signature (which
// would be `MinHeap<i32>` in this example).
let mut heap = MinHeap::new();

// We can use peek to look at the smallest item in the heap. In this case,
// there's no items in there yet so we get None.
assert_eq!(heap.peek(), None);

// Let's add some numbers...
heap.push(1);
heap.push(5);
heap.push(2);

// Now peek shows the smallest item in the heap.
assert_eq!(heap.peek(), Some(&1));

// We can check the length of a heap.
assert_eq!(heap.len(), 3);

// We can iterate over the items in the heap, although they are returned in
// an unspecified order.
for x in &heap {
    println!("{x}");
}

// If we instead pop these scores, they should come back in order.
assert_eq!(heap.pop(), Some(1));
assert_eq!(heap.pop(), Some(2));
assert_eq!(heap.pop(), Some(5));
assert_eq!(heap.pop(), None);

// We can clear the heap of any remaining items.
heap.clear();

// The heap should now be empty.
assert!(heap.is_empty())

When to use MinHeap?

By default, the BinaryHeap struct from std::collections is a max-heap, i.e. it provides efficient access and update to the largest element in a collection. To use it as a min-heap, one can either use core::cmp::Reverse or a custom Ord implementation, but this usually adds a lot of boilerplate to your code. This crate implements this boilerplate so that you never have to write it yourself again! It also allows you to use the derived Ord implementation instead of manually reversing it.

Here is a comparison of code without and with min_heap::MinHeap.

Reverse

// Without `MinHeap`
let mut heap = BinaryHeap::new();

heap.push(Reverse(1));
heap.push(Reverse(3));
heap.push(Reverse(5));

if let Some(Reverse(x)) = heap.pop() {
    println!("Min is {x}");
}

let heap_items: Vec<_> = heap.into_iter().map(|Reverse(x)| x).collect();
// With `MinHeap`
let mut heap = MinHeap::new();

heap.push(1);
heap.push(3);
heap.push(5);

if let Some(x) = heap.pop() {
    println!("Min is {x}");
}

let heap_items: Vec<_> = heap.into_iter().collect();

Custom Ord implementation

// Without `MinHeap`
#[derive(Copy, Clone, Eq, PartialEq)]
struct State {
    cost: usize,
    position: usize,
}

// The priority queue depends on `Ord`.
// Explicitly implement the trait so the queue becomes a min-heap
// instead of a max-heap.
impl Ord for State {
    fn cmp(&self, other: &Self) -> Ordering {
        // Notice that we flip the ordering on costs.
        // In case of a tie we compare positions - this step is necessary
        // to make implementations of `PartialEq` and `Ord` consistent.
        other.cost.cmp(&self.cost)
            .then_with(|| self.position.cmp(&other.position))
    }
}

// `PartialOrd` needs to be implemented as well.
impl PartialOrd for State {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

fn main() {
    let mut h = BinaryHeap::new();

    h.push(State { cost: 5, position: 1});
    h.push(State { cost: 3, position: 2});

    assert_eq!(h.pop(), Some(State {cost: 3, position: 2}))
}
// With `MinHeap`: we can use the derived implementation!
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
struct State {
    cost: usize,
    position: usize,
}

fn main() {
    let mut h = MinHeap::new();

    h.push(State { cost: 5, position: 1});
    h.push(State { cost: 3, position: 2});

    assert_eq!(h.pop(), Some(State {cost: 3, position: 2}))
}

Comparison with other min-heap crates

All other popular crates that provide min-heaps implementations are forks or reimplementations of BinaryHeap from the standard library, and some of them are no longer maintained. This crate provides a wrapper around the battle-tested BinaryHeap from std::collections, therefore it benefits from its updates and bug fixes.

Missing features

The unstable (nightly) features of BinaryHeap, such as the allocator API, are not available (yet!) in min_heap.

License

Licensed under either of Apache License, Version 2.0 or MIT license at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in min_heap by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
Commit count: 7

cargo fmt