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.
3
8
4
9
use std:: { cmp:: Ord , slice:: Iter } ;
5
10
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.
6
17
pub struct Heap < T > {
7
18
items : Vec < T > ,
8
19
comparator : fn ( & T , & T ) -> bool ,
9
20
}
10
21
11
22
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.
12
30
pub fn new ( comparator : fn ( & T , & T ) -> bool ) -> Self {
13
31
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.
18
32
items : vec ! [ ] ,
19
33
comparator,
20
34
}
21
35
}
22
36
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.
23
63
pub fn len ( & self ) -> usize {
24
64
self . items . len ( )
25
65
}
26
66
67
+ /// Checks if the heap is empty.
68
+ ///
69
+ /// # Returns
70
+ /// `true` if the heap is empty, `false` otherwise.
27
71
pub fn is_empty ( & self ) -> bool {
28
72
self . len ( ) == 0
29
73
}
30
74
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.
31
79
pub fn add ( & mut self , value : T ) {
32
80
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 ) ;
42
82
}
43
83
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`.
44
88
pub fn pop ( & mut self ) -> Option < T > {
45
89
if self . is_empty ( ) {
46
90
return None ;
47
91
}
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
51
92
let next = Some ( self . items . swap_remove ( 0 ) ) ;
52
-
53
93
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 ) ;
75
95
}
76
-
77
96
next
78
97
}
79
98
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.
80
103
pub fn iter ( & self ) -> Iter < ' _ , T > {
81
104
self . items . iter ( )
82
105
}
83
106
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`.
84
158
fn parent_idx ( & self , idx : usize ) -> Option < usize > {
85
159
if idx > 0 {
86
160
Some ( ( idx - 1 ) / 2 )
@@ -89,14 +163,35 @@ impl<T> Heap<T> {
89
163
}
90
164
}
91
165
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.
92
173
fn children_present ( & self , idx : usize ) -> bool {
93
- self . left_child_idx ( idx) <= ( self . len ( ) - 1 )
174
+ self . left_child_idx ( idx) < self . len ( )
94
175
}
95
176
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.
96
184
fn left_child_idx ( & self , idx : usize ) -> usize {
97
185
idx * 2 + 1
98
186
}
99
187
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.
100
195
fn right_child_idx ( & self , idx : usize ) -> usize {
101
196
self . left_child_idx ( idx) + 1
102
197
}
@@ -106,20 +201,49 @@ impl<T> Heap<T>
106
201
where
107
202
T : Ord ,
108
203
{
109
- /// Create a new MinHeap
204
+ /// Creates a new min-heap.
205
+ ///
206
+ /// # Returns
207
+ /// A new `Heap` instance configured as a min-heap.
110
208
pub fn new_min ( ) -> Heap < T > {
111
209
Self :: new ( |a, b| a < b)
112
210
}
113
211
114
- /// Create a new MaxHeap
212
+ /// Creates a new max-heap.
213
+ ///
214
+ /// # Returns
215
+ /// A new `Heap` instance configured as a max-heap.
115
216
pub fn new_max ( ) -> Heap < T > {
116
217
Self :: new ( |a, b| a > b)
117
218
}
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
+ }
118
241
}
119
242
120
243
#[ cfg( test) ]
121
244
mod tests {
122
245
use super :: * ;
246
+
123
247
#[ test]
124
248
fn test_empty_heap ( ) {
125
249
let mut heap: Heap < i32 > = Heap :: new_max ( ) ;
@@ -139,6 +263,8 @@ mod tests {
139
263
assert_eq ! ( heap. pop( ) , Some ( 9 ) ) ;
140
264
heap. add ( 1 ) ;
141
265
assert_eq ! ( heap. pop( ) , Some ( 1 ) ) ;
266
+ assert_eq ! ( heap. pop( ) , Some ( 11 ) ) ;
267
+ assert_eq ! ( heap. pop( ) , None ) ;
142
268
}
143
269
144
270
#[ test]
@@ -154,22 +280,8 @@ mod tests {
154
280
assert_eq ! ( heap. pop( ) , Some ( 4 ) ) ;
155
281
heap. add ( 1 ) ;
156
282
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 ) ;
173
285
}
174
286
175
287
#[ test]
@@ -180,20 +292,42 @@ mod tests {
180
292
heap. add ( 9 ) ;
181
293
heap. add ( 11 ) ;
182
294
183
- // test iterator, which is not in order except the first one.
184
295
let mut iter = heap. iter ( ) ;
185
296
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 ) ) ;
189
300
assert_eq ! ( iter. next( ) , None ) ;
190
301
191
- // test the heap after run iterator.
192
302
assert_eq ! ( heap. len( ) , 4 ) ;
193
303
assert_eq ! ( heap. pop( ) , Some ( 2 ) ) ;
194
304
assert_eq ! ( heap. pop( ) , Some ( 4 ) ) ;
195
305
assert_eq ! ( heap. pop( ) , Some ( 9 ) ) ;
196
306
assert_eq ! ( heap. pop( ) , Some ( 11 ) ) ;
197
307
assert_eq ! ( heap. pop( ) , None ) ;
198
308
}
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
+ }
199
333
}
0 commit comments