rustcomparatorbinary-heappartial-ordering

Why does BinaryHeap require Ord?


I am using the standard BinaryHeap as part of an algorithm where I need to retrieve the largest object (via some definition of largest). It could be possible that two non-equivalent elements are both equally large (and hence their relative order in the binary heap does not matter) - for example, I might be only interested in sorting on a single field of a multi-field struct.

Because of this, it would be somewhat unusual to have my type implement Ord and Eq. Instead, I should probably implement PartialOrd and PartialEq only. But, alas, BinaryHeap requires its elements to be Ord! Why is this so, and what is the most idiomatic way to use BinaryHeap with such types?

(As an aside, in C++, I would fairly easily write a custom comparator type in such a situation, and template the priority queue on the comparator type. So I don't think what I want to do is mathematically or algorithmically wrong.)


Solution

  • PartialOrd gives you asymmetric and transitive ordering, that is a < b implies !(a > b) and a < b && b < c implies a < c. PartialOrd does not require for all elements to actually have a meaningful ordering at all, which is why PartialOrd::partial_cmp returns an Option<Ordering> where None means "I don't know" (notice that this does not impair the aforementioned requirements).

    A binary heap requires total ordering for its elements, however, because a binary heap has to have the property that "the key stored in each node is either greater than or equal to (≥) or less than or equal to (≤) the keys in the node's children, according to some total order." (direct quote via Wikipedia).

    Only Ord gives you asymmetric, transitive and total (exactly one of a < b, a == b or a > b) ordering. The requirement for total order leads to Ord::cmp returning a Ordering, not a Option<Ordering>, because the None-case is not allowed.

    It is not uncommon the write specific implementations of PartialOrd and Ord in case you need specific behaviour. There is also the educe crate, which allows you to derive a more specific version of PartialOrd and Ord where certain fields are ignored.