From 81fcdd4af9c9e99cf2031c5f09a5f1a1dbf3bfc5 Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Fri, 13 Nov 2015 01:54:33 +0100 Subject: [PATCH] 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() --- src/libcollections/binary_heap.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/libcollections/binary_heap.rs b/src/libcollections/binary_heap.rs index 30fc22e400a..bdf5f5b2a83 100644 --- a/src/libcollections/binary_heap.rs +++ b/src/libcollections/binary_heap.rs @@ -521,29 +521,30 @@ impl BinaryHeap { while hole.pos() > start { let parent = (hole.pos() - 1) / 2; - if hole.removed() <= hole.get(parent) { break } + if hole.element() <= hole.get(parent) { break; } hole.move_to(parent); } } } - fn sift_down_range(&mut self, mut pos: usize, end: usize) { - let start = pos; + /// Take an element at `pos` and move it down the heap, + /// while its children are larger. + fn sift_down_range(&mut self, pos: usize, end: usize) { unsafe { let mut hole = Hole::new(&mut self.data, pos); let mut child = 2 * pos + 1; while child < end { let right = child + 1; + // compare with the greater of the two children if right < end && !(hole.get(child) > hole.get(right)) { child = right; } + // if we are already in order, stop. + if hole.element() >= hole.get(child) { break; } hole.move_to(child); child = 2 * hole.pos() + 1; } - - pos = hole.pos; } - self.sift_up(start, pos); } fn sift_down(&mut self, pos: usize) { @@ -605,7 +606,7 @@ impl<'a, T> Hole<'a, T> { /// Return a reference to the element removed #[inline(always)] - fn removed(&self) -> &T { + fn element(&self) -> &T { self.elt.as_ref().unwrap() }