Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I implement a min-heap of f64 with Rust's BinaryHeap?

Tags:

rust

min-heap

I want to populate a binary heap with floats--more specifically, I'd like to implement a min-heap.

It seems that floats do not support Ord and thus aren't usable out of the box. My attempts to wrap them have so far failed. However it seems that if I could wrap them then I could also implement Ord in such a way that it would effectively make BinaryHeap a min-heap.

Here's an example of a wrapper I tried:

#[derive(PartialEq, PartialOrd)]
struct MinNonNan(f64);

impl Eq for MinNonNan {}

impl Ord for MinNonNan {
    fn cmp(&self, other: &MinNonNan) -> Ordering {
        let ord = self.partial_cmp(other).unwrap();
        match ord {
            Ordering::Greater => Ordering::Less,
            Ordering::Less => Ordering::Greater,
            Ordering::Equal => ord
        }
    }
}

The problem is pop returns the values as though it were a max-heap.

What exactly do I need to do to populate a BinaryHeap with f64 values as a min-heap?

like image 793
maxcountryman Avatar asked Oct 10 '16 00:10

maxcountryman


People also ask

How do you initialize a min heap?

To build a min heap we:Create a new child node at the end of the heap (last level). Add the new key to that node (append it to the array). Move the child up until you reach the root node and the heap property is satisfied.

What is min heap and max heap in C++?

A Binary Heap is a complete binary tree which is either Min Heap or Max Heap. In a Max Binary Heap, the key at root must be maximum among all keys present in Binary Heap. This property must be recursively true for all nodes in Binary Tree. Min Binary Heap is similar to Min Heap.

What is minimum heap tree?

A Min Heap Binary Tree is a Binary Tree where the root node has the minimum key in the tree. The above definition holds true for all sub-trees in the tree. This is called the Min Heap property. Almost every node other than the last two layers must have two children.

What do you mean by Max Heap?

A max-heap is a complete binary tree in which the value in each internal node is greater than or equal to the values in the children of that node. Mapping the elements of a heap into an array is trivial: if a node is stored an index k, then its left child is stored at index 2k + 1 and its right child at index 2k + 2.


2 Answers

Crate-based solution

Instead of writing your own MinNonNan, consider using the ordered-float crate + the std::cmp::Reverse type.

type MinNonNan = Reverse<NotNan<f64>>;

Manual solution

Since you are #[derive]ing PartialOrd, the .gt(), .lt() etc methods still compare normally, i.e. MinNonNan(42.0) < MinNonNan(47.0) is still true. The Ord bound only restricts you to provide strictly-ordered types, it doesn't mean the implementation will use .cmp() instead of </>/<=/>= everywhere, nor the compiler will suddenly change those operators to use the Ord implementation.

If you want to flip the order, you need to implement PartialOrd as well.

#[derive(PartialEq)]
struct MinNonNan(f64);

impl PartialOrd for MinNonNan {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        other.0.partial_cmp(&self.0)
    }
}

impl Ord for MinNonNan {
    fn cmp(&self, other: &MinNonNan) -> Ordering {
        self.partial_cmp(other).unwrap()
    }
}
like image 139
kennytm Avatar answered Sep 25 '22 09:09

kennytm


Working Examples

Crate-based solution

use ordered_float::NotNan; // 2.7.0
use std::{cmp::Reverse, collections::BinaryHeap};

fn main() {
    let mut minheap = BinaryHeap::new();
    minheap.push(Reverse(NotNan::new(2.0).unwrap()));
    minheap.push(Reverse(NotNan::new(1.0).unwrap()));
    minheap.push(Reverse(NotNan::new(42.0).unwrap()));
    if let Some(Reverse(nn)) = minheap.pop() {
        println!("{}", nn.into_inner());
    }
}

Manual solution

use std::{cmp::Ordering, collections::BinaryHeap};

#[derive(PartialEq)]
struct MinNonNan(f64);

impl Eq for MinNonNan {}

impl PartialOrd for MinNonNan {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        other.0.partial_cmp(&self.0)
    }
}

impl Ord for MinNonNan {
    fn cmp(&self, other: &MinNonNan) -> Ordering {
        self.partial_cmp(other).unwrap()
    }
}

fn main() {
    let mut minheap = BinaryHeap::new();
    minheap.push(MinNonNan(2.0));
    minheap.push(MinNonNan(1.0));
    minheap.push(MinNonNan(42.0));
    if let Some(MinNonNan(root)) = minheap.pop() {
        println!("{:?}", root);
    }
}
like image 34
5 revs, 3 users 92% Avatar answered Sep 25 '22 09:09

5 revs, 3 users 92%