From ff17a417afb0734afb218ea30996d00d03134f2f Mon Sep 17 00:00:00 2001 From: Sergey Ilyevsky Date: Mon, 5 May 2025 10:59:25 +0300 Subject: [PATCH 1/2] Implement `from_vec` and `into_sorted_vec` for `BinaryHeap` --- CHANGELOG.md | 4 ++ src/binary_heap.rs | 97 +++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 92 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 72580d5b7c..e1caa54600 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### 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 31e2185fff..6c6e018bac 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, @@ -177,6 +172,37 @@ impl BinaryHeap { data: Vec::new(), } } + + /// Creates a new `BinaryHeap` from a `Vec`. + /// The heap uses the vector as its backing storage, no additional space is required. + /// The elements in the vector are rearranged to create the heap. + /// The time complexity is *O*(n). + /// + /// ``` + /// use heapless::binary_heap::{BinaryHeap, Max}; + /// use heapless::vec::Vec; + /// + /// let vec = Vec::from_array([4, 1, 8, 7, 3, 0, 6, 9, 2, 5]); + /// let heap: BinaryHeap<_, Max, 12> = BinaryHeap::from_vec(vec); + /// assert_eq!(heap.len(), 10); + /// assert_eq!(heap.capacity(), 12); + /// assert_eq!(heap.peek(), Some(&9)); + /// ``` + pub fn from_vec(vec: Vec) -> Self + where + T: Ord, + K: Kind + { + 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 BinaryHeap { @@ -184,6 +210,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 { @@ -411,7 +467,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 } @@ -463,8 +519,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); @@ -599,7 +654,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()); } } } @@ -890,4 +945,28 @@ 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_vec(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_vec(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)); + } } From 79c2471f8941d41269175450ea6d2887ca3b62b4 Mon Sep 17 00:00:00 2001 From: Sergey Ilyevsky Date: Mon, 5 May 2025 11:07:32 +0300 Subject: [PATCH 2/2] Fix style --- src/binary_heap.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/binary_heap.rs b/src/binary_heap.rs index 6c6e018bac..5f0637b69d 100644 --- a/src/binary_heap.rs +++ b/src/binary_heap.rs @@ -191,14 +191,14 @@ impl BinaryHeap { pub fn from_vec(vec: Vec) -> Self where T: Ord, - K: Kind + K: Kind, { let mut heap = Self { _kind: PhantomData, data: vec, }; let len = heap.len(); - for i in (0..len/2).rev() { + for i in (0..len / 2).rev() { heap.sift_down_to_bottom(i, len); } heap @@ -954,7 +954,10 @@ mod tests { let heap: BinaryHeap = BinaryHeap::from_vec(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]); + assert_eq!( + &heap.into_vec(), + &[0, 1, 3, 6, 2, 4, 12, 8, 9, 7, 5, 11, 10] + ); } #[test]