BinaryHeap: Simplify sift down#29811
Conversation
|
(rust_highfive has picked a reviewer for you, use r? to override) |
302c292 to
cee674f
Compare
|
I don't quite understand why sift down was so complicated to start with. It's certainly not needed for heapify, push or pop, but something else? |
4393a5c to
75c0972
Compare
src/libcollections/binary_heap.rs
Outdated
|
I'm guessing this was an artifact of refactoring that wasn't caught in prior review. I'm nervous about this just because I don't understand what the old code was trying to do. |
src/libcollections/binary_heap.rs
Outdated
There was a problem hiding this comment.
iirc the style is to add the semi after the break?
|
I double checked the defn of heap sort, and this seems to check out. r=me with nits |
Sift down was doing all too much work: it can stop directly when the current element obeys the heap property in relation to its children. In the old code, sift down didn't compare the element to sift down at all, so it was maximally sifted down and relied on the sift up call to put it in the correct location. This should speed up heapify and .pop(). Also rename Hole::removed() to Hole::element()
75c0972 to
81fcdd4
Compare
|
Applied the fixes, and improved the commit log text to point out why the old code worked. Thank you for the review! |
|
@bors r=gankro |
|
📌 Commit 81fcdd4 has been approved by |
BinaryHeap: Simplify sift down Sift down was doing all too much work: it can stop directly when the current element obeys the heap property in relation to its children. In the old code, sift down didn't compare the element to sift down at all, so it was maximally sifted down and relied on the sift up call to put it in the correct location. This should speed up heapify and .pop(). Also rename Hole::removed() to Hole::element()
|
Here's a microbenchmark Comparing rust versions: It suggest a slight improvment with this PR. It's a minimum spanning tree computation on a graph of 450 edges. The algorithm spends most of its time popping off the least edge from a BinaryHeap, and its runtime improves slightly: |
|
From the Python source code, which also maximally sifts down and then back up: I think this change could use some more benchmarks; I suspect whether you win or lose performance depends on how expensive the comparison function is compared to moving elements around in memory. |
|
@dgrunwald In Python, list element swaps are very cheap (one PyObject *), and comparisons expensive (python function call). |
|
Indeed, in the same kind of benchmark where the edge weight is a type with more expensive comparison function ( Maybe we can use separate sift_down methods for pop and for heapify (BinaryHeap::from). |
BinaryHeap: Simplify sift down
Sift down was doing all too much work: it can stop directly when the
current element obeys the heap property in relation to its children.
In the old code, sift down didn't compare the element to sift down at
all, so it was maximally sifted down and relied on the sift up call to
put it in the correct location.
This should speed up heapify and .pop().
Also rename Hole::removed() to Hole::element()