Skip to content

Commit 84c4665

Browse files
authored
Improve Heap Implementation (#785)
* ref: add `from_vec` method to create heap from vector * chore: update docstrings
1 parent 77da9fe commit 84c4665

File tree

1 file changed

+199
-65
lines changed

1 file changed

+199
-65
lines changed

src/data_structures/heap.rs

Lines changed: 199 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,86 +1,160 @@
1-
// Heap data structure
2-
// Takes a closure as a comparator to allow for min-heap, max-heap, and works with custom key functions
1+
//! A generic heap data structure.
2+
//!
3+
//! This module provides a `Heap` implementation that can function as either a
4+
//! min-heap or a max-heap. It supports common heap operations such as adding,
5+
//! removing, and iterating over elements. The heap can also be created from
6+
//! an unsorted vector and supports custom comparators for flexible sorting
7+
//! behavior.
38
49
use std::{cmp::Ord, slice::Iter};
510

11+
/// A heap data structure that can be used as a min-heap, max-heap or with
12+
/// custom comparators.
13+
///
14+
/// This struct manages a collection of items where the heap property is maintained.
15+
/// The heap can be configured to order elements based on a provided comparator function,
16+
/// allowing for both min-heap and max-heap functionalities, as well as custom sorting orders.
617
pub struct Heap<T> {
718
items: Vec<T>,
819
comparator: fn(&T, &T) -> bool,
920
}
1021

1122
impl<T> Heap<T> {
23+
/// Creates a new, empty heap with a custom comparator function.
24+
///
25+
/// # Parameters
26+
/// - `comparator`: A function that defines the heap's ordering.
27+
///
28+
/// # Returns
29+
/// A new `Heap` instance.
1230
pub fn new(comparator: fn(&T, &T) -> bool) -> Self {
1331
Self {
14-
// Add a default in the first spot to offset indexes
15-
// for the parent/child math to work out.
16-
// Vecs have to have all the same type so using Default
17-
// is a way to add an unused item.
1832
items: vec![],
1933
comparator,
2034
}
2135
}
2236

37+
/// Creates a heap from a vector and a custom comparator function.
38+
///
39+
/// # Parameters
40+
/// - `items`: A vector of items to be turned into a heap.
41+
/// - `comparator`: A function that defines the heap's ordering.
42+
///
43+
/// # Returns
44+
/// A `Heap` instance with the elements from the provided vector.
45+
pub fn from_vec(items: Vec<T>, comparator: fn(&T, &T) -> bool) -> Self {
46+
let mut heap = Self { items, comparator };
47+
heap.build_heap();
48+
heap
49+
}
50+
51+
/// Constructs the heap from an unsorted vector by applying the heapify process.
52+
fn build_heap(&mut self) {
53+
let last_parent_idx = (self.len() / 2).wrapping_sub(1);
54+
for idx in (0..=last_parent_idx).rev() {
55+
self.heapify_down(idx);
56+
}
57+
}
58+
59+
/// Returns the number of elements in the heap.
60+
///
61+
/// # Returns
62+
/// The number of elements in the heap.
2363
pub fn len(&self) -> usize {
2464
self.items.len()
2565
}
2666

67+
/// Checks if the heap is empty.
68+
///
69+
/// # Returns
70+
/// `true` if the heap is empty, `false` otherwise.
2771
pub fn is_empty(&self) -> bool {
2872
self.len() == 0
2973
}
3074

75+
/// Adds a new element to the heap and maintains the heap property.
76+
///
77+
/// # Parameters
78+
/// - `value`: The value to add to the heap.
3179
pub fn add(&mut self, value: T) {
3280
self.items.push(value);
33-
34-
// Heapify Up
35-
let mut idx = self.len() - 1;
36-
while let Some(pdx) = self.parent_idx(idx) {
37-
if (self.comparator)(&self.items[idx], &self.items[pdx]) {
38-
self.items.swap(idx, pdx);
39-
}
40-
idx = pdx;
41-
}
81+
self.heapify_up(self.len() - 1);
4282
}
4383

84+
/// Removes and returns the root element from the heap.
85+
///
86+
/// # Returns
87+
/// The root element if the heap is not empty, otherwise `None`.
4488
pub fn pop(&mut self) -> Option<T> {
4589
if self.is_empty() {
4690
return None;
4791
}
48-
// This feels like a function built for heap impl :)
49-
// Removes an item at an index and fills in with the last item
50-
// of the Vec
5192
let next = Some(self.items.swap_remove(0));
52-
5393
if !self.is_empty() {
54-
// Heapify Down
55-
let mut idx = 0;
56-
while self.children_present(idx) {
57-
let cdx = {
58-
if self.right_child_idx(idx) >= self.len() {
59-
self.left_child_idx(idx)
60-
} else {
61-
let ldx = self.left_child_idx(idx);
62-
let rdx = self.right_child_idx(idx);
63-
if (self.comparator)(&self.items[ldx], &self.items[rdx]) {
64-
ldx
65-
} else {
66-
rdx
67-
}
68-
}
69-
};
70-
if !(self.comparator)(&self.items[idx], &self.items[cdx]) {
71-
self.items.swap(idx, cdx);
72-
}
73-
idx = cdx;
74-
}
94+
self.heapify_down(0);
7595
}
76-
7796
next
7897
}
7998

99+
/// Returns an iterator over the elements in the heap.
100+
///
101+
/// # Returns
102+
/// An iterator over the elements in the heap, in their internal order.
80103
pub fn iter(&self) -> Iter<'_, T> {
81104
self.items.iter()
82105
}
83106

107+
/// Moves an element upwards to restore the heap property.
108+
///
109+
/// # Parameters
110+
/// - `idx`: The index of the element to heapify up.
111+
fn heapify_up(&mut self, mut idx: usize) {
112+
while let Some(pdx) = self.parent_idx(idx) {
113+
if (self.comparator)(&self.items[idx], &self.items[pdx]) {
114+
self.items.swap(idx, pdx);
115+
idx = pdx;
116+
} else {
117+
break;
118+
}
119+
}
120+
}
121+
122+
/// Moves an element downwards to restore the heap property.
123+
///
124+
/// # Parameters
125+
/// - `idx`: The index of the element to heapify down.
126+
fn heapify_down(&mut self, mut idx: usize) {
127+
while self.children_present(idx) {
128+
let cdx = {
129+
if self.right_child_idx(idx) >= self.len() {
130+
self.left_child_idx(idx)
131+
} else {
132+
let ldx = self.left_child_idx(idx);
133+
let rdx = self.right_child_idx(idx);
134+
if (self.comparator)(&self.items[ldx], &self.items[rdx]) {
135+
ldx
136+
} else {
137+
rdx
138+
}
139+
}
140+
};
141+
142+
if (self.comparator)(&self.items[cdx], &self.items[idx]) {
143+
self.items.swap(idx, cdx);
144+
idx = cdx;
145+
} else {
146+
break;
147+
}
148+
}
149+
}
150+
151+
/// Returns the index of the parent of the element at `idx`.
152+
///
153+
/// # Parameters
154+
/// - `idx`: The index of the element.
155+
///
156+
/// # Returns
157+
/// The index of the parent element if it exists, otherwise `None`.
84158
fn parent_idx(&self, idx: usize) -> Option<usize> {
85159
if idx > 0 {
86160
Some((idx - 1) / 2)
@@ -89,14 +163,35 @@ impl<T> Heap<T> {
89163
}
90164
}
91165

166+
/// Checks if the element at `idx` has children.
167+
///
168+
/// # Parameters
169+
/// - `idx`: The index of the element.
170+
///
171+
/// # Returns
172+
/// `true` if the element has children, `false` otherwise.
92173
fn children_present(&self, idx: usize) -> bool {
93-
self.left_child_idx(idx) <= (self.len() - 1)
174+
self.left_child_idx(idx) < self.len()
94175
}
95176

177+
/// Returns the index of the left child of the element at `idx`.
178+
///
179+
/// # Parameters
180+
/// - `idx`: The index of the element.
181+
///
182+
/// # Returns
183+
/// The index of the left child.
96184
fn left_child_idx(&self, idx: usize) -> usize {
97185
idx * 2 + 1
98186
}
99187

188+
/// Returns the index of the right child of the element at `idx`.
189+
///
190+
/// # Parameters
191+
/// - `idx`: The index of the element.
192+
///
193+
/// # Returns
194+
/// The index of the right child.
100195
fn right_child_idx(&self, idx: usize) -> usize {
101196
self.left_child_idx(idx) + 1
102197
}
@@ -106,20 +201,49 @@ impl<T> Heap<T>
106201
where
107202
T: Ord,
108203
{
109-
/// Create a new MinHeap
204+
/// Creates a new min-heap.
205+
///
206+
/// # Returns
207+
/// A new `Heap` instance configured as a min-heap.
110208
pub fn new_min() -> Heap<T> {
111209
Self::new(|a, b| a < b)
112210
}
113211

114-
/// Create a new MaxHeap
212+
/// Creates a new max-heap.
213+
///
214+
/// # Returns
215+
/// A new `Heap` instance configured as a max-heap.
115216
pub fn new_max() -> Heap<T> {
116217
Self::new(|a, b| a > b)
117218
}
219+
220+
/// Creates a min-heap from an unsorted vector.
221+
///
222+
/// # Parameters
223+
/// - `items`: A vector of items to be turned into a min-heap.
224+
///
225+
/// # Returns
226+
/// A `Heap` instance configured as a min-heap.
227+
pub fn from_vec_min(items: Vec<T>) -> Heap<T> {
228+
Self::from_vec(items, |a, b| a < b)
229+
}
230+
231+
/// Creates a max-heap from an unsorted vector.
232+
///
233+
/// # Parameters
234+
/// - `items`: A vector of items to be turned into a max-heap.
235+
///
236+
/// # Returns
237+
/// A `Heap` instance configured as a max-heap.
238+
pub fn from_vec_max(items: Vec<T>) -> Heap<T> {
239+
Self::from_vec(items, |a, b| a > b)
240+
}
118241
}
119242

120243
#[cfg(test)]
121244
mod tests {
122245
use super::*;
246+
123247
#[test]
124248
fn test_empty_heap() {
125249
let mut heap: Heap<i32> = Heap::new_max();
@@ -139,6 +263,8 @@ mod tests {
139263
assert_eq!(heap.pop(), Some(9));
140264
heap.add(1);
141265
assert_eq!(heap.pop(), Some(1));
266+
assert_eq!(heap.pop(), Some(11));
267+
assert_eq!(heap.pop(), None);
142268
}
143269

144270
#[test]
@@ -154,22 +280,8 @@ mod tests {
154280
assert_eq!(heap.pop(), Some(4));
155281
heap.add(1);
156282
assert_eq!(heap.pop(), Some(2));
157-
}
158-
159-
#[allow(dead_code)]
160-
struct Point(/* x */ i32, /* y */ i32);
161-
162-
#[test]
163-
fn test_key_heap() {
164-
let mut heap: Heap<Point> = Heap::new(|a, b| a.0 < b.0);
165-
heap.add(Point(1, 5));
166-
heap.add(Point(3, 10));
167-
heap.add(Point(-2, 4));
168-
assert_eq!(heap.len(), 3);
169-
assert_eq!(heap.pop().unwrap().0, -2);
170-
assert_eq!(heap.pop().unwrap().0, 1);
171-
heap.add(Point(50, 34));
172-
assert_eq!(heap.pop().unwrap().0, 3);
283+
assert_eq!(heap.pop(), Some(1));
284+
assert_eq!(heap.pop(), None);
173285
}
174286

175287
#[test]
@@ -180,20 +292,42 @@ mod tests {
180292
heap.add(9);
181293
heap.add(11);
182294

183-
// test iterator, which is not in order except the first one.
184295
let mut iter = heap.iter();
185296
assert_eq!(iter.next(), Some(&2));
186-
assert_ne!(iter.next(), None);
187-
assert_ne!(iter.next(), None);
188-
assert_ne!(iter.next(), None);
297+
assert_eq!(iter.next(), Some(&4));
298+
assert_eq!(iter.next(), Some(&9));
299+
assert_eq!(iter.next(), Some(&11));
189300
assert_eq!(iter.next(), None);
190301

191-
// test the heap after run iterator.
192302
assert_eq!(heap.len(), 4);
193303
assert_eq!(heap.pop(), Some(2));
194304
assert_eq!(heap.pop(), Some(4));
195305
assert_eq!(heap.pop(), Some(9));
196306
assert_eq!(heap.pop(), Some(11));
197307
assert_eq!(heap.pop(), None);
198308
}
309+
310+
#[test]
311+
fn test_from_vec_min() {
312+
let vec = vec![3, 1, 4, 1, 5, 9, 2, 6, 5];
313+
let mut heap = Heap::from_vec_min(vec);
314+
assert_eq!(heap.len(), 9);
315+
assert_eq!(heap.pop(), Some(1));
316+
assert_eq!(heap.pop(), Some(1));
317+
assert_eq!(heap.pop(), Some(2));
318+
heap.add(0);
319+
assert_eq!(heap.pop(), Some(0));
320+
}
321+
322+
#[test]
323+
fn test_from_vec_max() {
324+
let vec = vec![3, 1, 4, 1, 5, 9, 2, 6, 5];
325+
let mut heap = Heap::from_vec_max(vec);
326+
assert_eq!(heap.len(), 9);
327+
assert_eq!(heap.pop(), Some(9));
328+
assert_eq!(heap.pop(), Some(6));
329+
assert_eq!(heap.pop(), Some(5));
330+
heap.add(10);
331+
assert_eq!(heap.pop(), Some(10));
332+
}
199333
}

0 commit comments

Comments
 (0)