Skip to content

Commit 1586005

Browse files
committed
Auto merge of #30534 - bluss:binary-heap-fast-pop, r=Gankro
BinaryHeap: Use full sift down in .pop() .sift_down can either choose to compare the element on the way down (and place it during descent), or to sift down an element fully, then sift back up to place it. A previous PR changed .sift_down() to the former behavior, which is much faster for relatively small heaps and for elements that are cheap to compare. A benchmarking run suggested that BinaryHeap::pop() suffers improportionally from this, and that it should use the second strategy instead. It's logical since .pop() brings last element from the heapified vector into index 0, it's very likely that this element will end up at the bottom again. Closes #29969 Previous PR #29811
2 parents 0672ed4 + 52883ab commit 1586005

File tree

1 file changed

+26
-1
lines changed

1 file changed

+26
-1
lines changed

src/libcollections/binary_heap.rs

+26-1
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@ impl<T: Ord> BinaryHeap<T> {
354354
self.data.pop().map(|mut item| {
355355
if !self.is_empty() {
356356
swap(&mut item, &mut self.data[0]);
357-
self.sift_down(0);
357+
self.sift_down_to_bottom(0);
358358
}
359359
item
360360
})
@@ -545,6 +545,31 @@ impl<T: Ord> BinaryHeap<T> {
545545
self.sift_down_range(pos, len);
546546
}
547547

548+
/// Take an element at `pos` and move it all the way down the heap,
549+
/// then sift it up to its position.
550+
///
551+
/// Note: This is faster when the element is known to be large / should
552+
/// be closer to the bottom.
553+
fn sift_down_to_bottom(&mut self, mut pos: usize) {
554+
let end = self.len();
555+
let start = pos;
556+
unsafe {
557+
let mut hole = Hole::new(&mut self.data, pos);
558+
let mut child = 2 * pos + 1;
559+
while child < end {
560+
let right = child + 1;
561+
// compare with the greater of the two children
562+
if right < end && !(hole.get(child) > hole.get(right)) {
563+
child = right;
564+
}
565+
hole.move_to(child);
566+
child = 2 * hole.pos() + 1;
567+
}
568+
pos = hole.pos;
569+
}
570+
self.sift_up(start, pos);
571+
}
572+
548573
/// Returns the length of the binary heap.
549574
#[stable(feature = "rust1", since = "1.0.0")]
550575
pub fn len(&self) -> usize {

0 commit comments

Comments
 (0)