diff --git a/CHANGELOG.md b/CHANGELOG.md index d21f26cbb7..57c8e7c853 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,10 @@ of panicking drop implementations. - Added optional `embedded_io::Write` impl for `Vec`. +### Added + +- Added `from_vec` and `into_sorted_vec` implementations for `BinaryHeap`. + ### Changed - `bytes::BufMut` is now implemented on `VecInner`. diff --git a/src/binary_heap.rs b/src/binary_heap.rs index 452b84a13e..f3dcc43768 100644 --- a/src/binary_heap.rs +++ b/src/binary_heap.rs @@ -3,11 +3,6 @@ //! Insertion and popping the largest element have *O*(log n) time complexity. //! Checking the smallest/largest element is *O*(1). -// TODO not yet implemented -// Converting a vector to a binary heap can be done in-place, and has *O*(n) complexity. A binary -// heap can also be converted to a sorted vector in-place, allowing it to be used for an -// *O*(n log n) in-place heapsort. - use core::{ cmp::Ordering, fmt, @@ -192,6 +187,36 @@ impl BinaryHeap { pub fn into_vec(self) -> Vec { self.data } + + /// Returns the underlying `Vec` sorted in ascending order. + /// The time complexity is *O*(n log n). + /// + /// ``` + /// use heapless::binary_heap::{BinaryHeap, Max}; + /// + /// let mut heap: BinaryHeap<_, Max, 4> = BinaryHeap::new(); + /// heap.push(4).unwrap(); + /// heap.push(2).unwrap(); + /// heap.push(8).unwrap(); + /// heap.push(1).unwrap(); + /// assert_eq!(heap.into_sorted_vec(), [1, 2, 4, 8]); + /// ``` + pub fn into_sorted_vec(mut self) -> Vec + where + K: Kind, + T: Ord, + { + let mut i = self.data.len(); + while i > 0 { + i -= 1; + unsafe { + let p = self.data.as_mut_ptr(); + ptr::swap(p, p.add(i)); + } + self.sift_down_to_bottom(0, i); + } + self.data + } } impl> BinaryHeapInner { @@ -419,7 +444,7 @@ where if !self.is_empty() { mem::swap(&mut item, self.data.as_mut_slice().get_unchecked_mut(0)); - self.sift_down_to_bottom(0); + self.sift_down_to_bottom(0, self.len()); } item } @@ -471,8 +496,7 @@ where } /* Private API */ - fn sift_down_to_bottom(&mut self, mut pos: usize) { - let end = self.len(); + fn sift_down_to_bottom(&mut self, mut pos: usize, end: usize) { let start = pos; unsafe { let mut hole = Hole::new(self.data.as_mut_slice(), pos); @@ -607,7 +631,7 @@ where { fn drop(&mut self) { if self.sift { - self.heap.sift_down_to_bottom(0); + self.heap.sift_down_to_bottom(0, self.heap.len()); } } } @@ -687,6 +711,19 @@ where } } +impl From> for BinaryHeap { + fn from(vec: Vec) -> Self { + let mut heap = Self { + _kind: PhantomData, + data: vec, + }; + let len = heap.len(); + for i in (0..len / 2).rev() { + heap.sift_down_to_bottom(i, len); + } + heap + } +} impl fmt::Debug for BinaryHeapInner where K: Kind, @@ -916,4 +953,31 @@ mod tests { ) -> &'c BinaryHeapView<&'b (), Max> { x } + + #[test] + fn from_vec() { + use crate::vec::Vec; + + let src: Vec<_, 16, _> = Vec::from_array([4, 1, 12, 8, 7, 3, 0, 6, 9, 2, 5, 11, 10]); + let heap: BinaryHeap = BinaryHeap::from(src); + assert_eq!(heap.len(), 13); + assert_eq!(heap.capacity(), 16); + assert_eq!( + &heap.into_vec(), + &[0, 1, 3, 6, 2, 4, 12, 8, 9, 7, 5, 11, 10] + ); + } + + #[test] + fn into_sorted_vec() { + use crate::vec::Vec; + use core::array; + + let src: Vec<_, 16, _> = Vec::from_array([4, 1, 12, 8, 7, 3, 0, 6, 9, 2, 5, 11, 10]); + let heap: BinaryHeap = BinaryHeap::from(src); + let dst = heap.into_sorted_vec(); + assert_eq!(dst.len(), 13); + assert_eq!(dst.capacity(), 16); + assert_eq!(&dst, &array::from_fn::(|x| 12 - x as u8)); + } }