tree_experiments/binary_heap.rs
1// SPDX-FileCopyrightText: 2023 Markus Mayer
2// SPDX-License-Identifier: EUPL-1.2
3
4use std::fmt::{Debug, Formatter};
5use std::marker::PhantomData;
6use std::mem::swap;
7
8/// A binary max-heap.
9///
10/// Uses a list representation internally.
11pub type BinaryMaxHeap<T> = BinaryHeap<T, Max<T>>;
12
13/// A binary max-heap.
14///
15/// Uses a list representation internally.
16pub type BinaryMinHeap<T> = BinaryHeap<T, Min<T>>;
17
18/// A binary tree with an arbitrary heap property.
19pub struct BinaryHeap<T, H> {
20 /// The heap in list representation.
21 ///
22 /// ## List representation
23 ///
24 /// An element at index `N` has its left child at index `2×N+1` and its right child at `2×N+2`.
25 /// The parent of a non-root element at `N>0` can be found at index `(N-1)/2`.
26 ///
27 /// ## Complete Binary Tree
28 ///
29 /// The heap is implemented as a complete binary tree, i.e. all levels are completely filled,
30 /// except for possibly the last level, i.e. all children are as far left as possible, and a
31 /// node has either both a left and right child, just a left child or no children at all.
32 data: Vec<T>,
33 _heap_property: PhantomData<H>,
34}
35
36/// Implements the max-heap property.
37pub struct Max<T>(PhantomData<T>);
38
39/// Implements the min-heap property.
40pub struct Min<T>(PhantomData<T>);
41
42/// Heap property.
43pub trait HeapProperty<T> {
44 const NAME: &'static str;
45
46 /// Determines whether the heap property is upheld between the first and the
47 /// second value, where the first value takes priority:
48 ///
49 /// * `property_upheld(parent, child)`
50 /// * `property_upheld(left, right)`
51 fn property_upheld(lhs: &T, rhs: &T) -> bool;
52}
53
54impl<T, H> BinaryHeap<T, H> {
55 /// Constructs a new, empty `BinaryHeap`.
56 pub const fn new() -> Self {
57 Self {
58 data: Vec::new(),
59 _heap_property: PhantomData,
60 }
61 }
62
63 /// Constructs a new, empty `BinaryHeap` with at least the specified capacity.
64 pub fn with_capacity(capacity: usize) -> Self {
65 Self {
66 data: Vec::with_capacity(capacity),
67 _heap_property: PhantomData,
68 }
69 }
70
71 /// Pushes an element onto the heap.
72 ///
73 /// ## Arguments
74 ///
75 /// * `value` - The value to push onto the heap.
76 pub fn push(&mut self, value: T)
77 where
78 T: PartialOrd,
79 H: HeapProperty<T>,
80 {
81 let index = self.data.len();
82 self.data.push(value);
83 self.upheap(index);
84 }
85
86 /// Gets a reference to the top element on the heap.
87 ///
88 /// ## Returns
89 ///
90 /// A value if the tree is nonempty; or `None` otherwise.
91 pub fn peek(&self) -> Option<&T> {
92 self.data.get(0)
93 }
94
95 /// Extracts an element from the heap.
96 ///
97 /// ## Returns
98 ///
99 /// A value if the tree is nonempty; or `None` otherwise.
100 pub fn pop(&mut self) -> Option<T>
101 where
102 T: PartialOrd,
103 H: HeapProperty<T>,
104 {
105 if self.data.is_empty() {
106 return None;
107 }
108
109 // Replace the root of the heap with the last element on the last level.
110 let last_index = self.data.len() - 1;
111 self.data.swap(0, last_index);
112
113 // We extract the last element first so it doesn't interfere with the downheap operation.
114 let extracted_value = self.data.pop();
115
116 if !self.data.is_empty() {
117 self.downheap(0);
118 }
119
120 extracted_value
121 }
122
123 /// Pushes an element onto the heap and extracts the top value in one operation.
124 ///
125 /// ## Arguments
126 ///
127 /// * `value` - The value to push onto the heap.
128 ///
129 /// ## Returns
130 ///
131 /// The value. If the tree is empty, the value itself is returned.
132 pub fn push_pop(&mut self, mut value: T) -> T
133 where
134 T: PartialOrd,
135 H: HeapProperty<T>,
136 {
137 if self.data.is_empty() {
138 return value;
139 }
140
141 if H::property_upheld(&value, &self.data[0]) {
142 return value;
143 }
144
145 swap(&mut self.data[0], &mut value);
146 self.downheap(0);
147
148 value
149 }
150
151 /// Determines whether the heap contains the specified item.
152 ///
153 /// ## Arguments
154 ///
155 /// * `value` - The value to test for.
156 ///
157 /// ## Returns
158 ///
159 /// Returns `true` if the heap contains the specified item or `false` if not.
160 pub fn contains(&self, value: &T) -> bool
161 where
162 T: PartialEq,
163 {
164 self.data.contains(value)
165 }
166
167 /// Deletes a value from the heap.
168 ///
169 /// ## Arguments
170 ///
171 /// * `value` - The value to delete.
172 ///
173 /// ## Returns
174 ///
175 /// Returns `true` if the value was deleted or `false` if not.
176 pub fn remove(&mut self, value: &T) -> bool
177 where
178 T: PartialEq + PartialOrd,
179 H: HeapProperty<T>,
180 {
181 self.remove_where(|x| x == value).is_some()
182 }
183
184 /// Deletes a value from the heap.
185 ///
186 /// ## Arguments
187 ///
188 /// * `predicate` - The predicate used to test for the value. If the predicate matches,
189 /// the value is removed and the function returns.
190 ///
191 /// ## Returns
192 ///
193 /// Returns `Some(value)` if the value was deleted or `None` if not.
194 pub fn remove_where<F>(&mut self, predicate: F) -> Option<T>
195 where
196 T: PartialEq + PartialOrd,
197 H: HeapProperty<T>,
198 F: FnMut(&T) -> bool,
199 {
200 if self.data.is_empty() {
201 return None;
202 }
203
204 let last_index = self.data.len() - 1;
205
206 // Find the index of the element we want to delete.
207 if let Some(index) = self.data.iter().position(predicate) {
208 // Swap this element with the last element.
209 self.data.swap(index, last_index);
210
211 // Remove the element.
212 let previous_value = self.data.pop().expect("the value exists");
213
214 // If we deleted the last element, exit.
215 if index == last_index {
216 return Some(previous_value);
217 }
218
219 // Down-heapify or up-heapify to restore the heap property.
220 let up_heapify = H::property_upheld(&self.data[index], &previous_value);
221 if up_heapify {
222 self.upheap(index);
223 } else {
224 self.downheap(index);
225 }
226
227 Some(previous_value)
228 } else {
229 None
230 }
231 }
232
233 /// Replaces a value on the heap.
234 ///
235 /// This function can be used if the replacement value already exists. If the element needs
236 /// to be mutated in place, use [`BinaryHeap::replace_where_with`] instead.
237 ///
238 /// ## Arguments
239 ///
240 /// * `value` - The value to replace.
241 /// * `replacement` - The replacement value.
242 ///
243 /// ## Returns
244 ///
245 /// Returns `Some(previous value)` if the value was replaced or `None` if not.
246 pub fn replace(&mut self, value: &T, replacement: T) -> Option<T>
247 where
248 T: PartialEq + PartialOrd,
249 H: HeapProperty<T>,
250 {
251 self.replace_where(|x| x == value, replacement)
252 }
253
254 /// Replaces a value on the heap.
255 ///
256 /// This function can be used if the replacement value already exists. If the element needs
257 /// to be mutated in place, use [`BinaryHeap::replace_where_with`] instead.
258 ///
259 /// ## Arguments
260 ///
261 /// * `predicate` - The predicate used to test for the value. If the predicate matches,
262 /// the value is removed and the function returns.
263 /// * `replacement` - The replacement value.
264 ///
265 /// ## Returns
266 ///
267 /// Returns `Some(previous value)` if the value was replaced or `None` if not.
268 pub fn replace_where<F>(&mut self, predicate: F, mut replacement: T) -> Option<T>
269 where
270 T: PartialEq + PartialOrd,
271 H: HeapProperty<T>,
272 F: FnMut(&T) -> bool,
273 {
274 if self.data.is_empty() {
275 return None;
276 }
277
278 // Find the index of the element we want to delete.
279 if let Some(index) = self.data.iter().position(predicate) {
280 let downheap = H::property_upheld(&self.data[index], &replacement);
281
282 swap(&mut self.data[index], &mut replacement);
283
284 if downheap {
285 self.downheap(index);
286 } else {
287 self.upheap(index);
288 }
289
290 Some(replacement)
291 } else {
292 None
293 }
294 }
295
296 /// Replaces a value on the heap.
297 ///
298 /// This function allows to mutate the value in-place but at the cost of a bit of performance.
299 /// If the replacement value exists beforehand, use [`BinaryHeap::replace_where`] instead.
300 ///
301 /// ## Arguments
302 ///
303 /// * `value` - The value to replace.
304 /// * `replacement` - The function creating the replacement value.
305 ///
306 /// ## Returns
307 ///
308 /// Returns `true` if the value was replaced or `false` if not.
309 pub fn replace_with<R>(&mut self, value: &T, replacement: R) -> bool
310 where
311 T: PartialEq + PartialOrd,
312 H: HeapProperty<T>,
313 R: FnMut(&mut T),
314 {
315 self.replace_where_with(|x| x == value, replacement)
316 }
317
318 /// Replaces a value on the heap.
319 ///
320 /// This function allows to mutate the value in-place but at the cost of a bit of performance.
321 /// If the replacement value exists beforehand, use [`BinaryHeap::replace_where`] instead.
322 ///
323 /// ## Arguments
324 ///
325 /// * `predicate` - The predicate used to test for the value. If the predicate matches,
326 /// the value is removed and the function returns.
327 /// * `replacement` - The function creating the replacement value.
328 ///
329 /// ## Returns
330 ///
331 /// Returns `true` if the value was replaced or `false` if not.
332 pub fn replace_where_with<F, R>(&mut self, predicate: F, mut replacement: R) -> bool
333 where
334 T: PartialEq + PartialOrd,
335 H: HeapProperty<T>,
336 F: FnMut(&T) -> bool,
337 R: FnMut(&mut T),
338 {
339 if self.data.is_empty() {
340 return false;
341 }
342
343 // Find the index of the element we want to delete.
344 if let Some(index) = self.data.iter().position(predicate) {
345 // Mutate the element.
346 replacement(&mut self.data[index]);
347
348 // TODO: Optimize these calls? We don't know if the value increased or decreased here.
349 let _ = self.upheap(index) || self.downheap(index);
350
351 true
352 } else {
353 false
354 }
355 }
356
357 /// Returns the number of elements on the heap.
358 pub fn len(&self) -> usize {
359 self.data.len()
360 }
361
362 /// Returns `true` if the heap is empty.
363 pub fn is_empty(&self) -> bool {
364 self.data.is_empty()
365 }
366
367 /// Ensures that elements are in the correct order, starting from a given child node,
368 /// working its way up the heap.
369 ///
370 /// ## Returns
371 ///
372 /// Returns `true` if the tree was changed or `false` if no change was performed.
373 fn upheap(&mut self, mut index: usize) -> bool
374 where
375 T: PartialOrd,
376 H: HeapProperty<T>,
377 {
378 debug_assert!(index < self.data.len());
379 let mut changed = false;
380
381 // Compare the added element with its parent; if they are in the correct order, stop.
382 while index > 0 {
383 let parent_idx = self
384 .get_parent_idx(index)
385 .expect("since the tree was not empty before the insert, the parent must exist");
386
387 let parent = self
388 .data
389 .get(parent_idx)
390 .expect("since the tree was not empty before the insert, the parent must exist");
391
392 if H::property_upheld(&parent, &self.data[index]) {
393 break;
394 }
395
396 // If not, swap the element with its parent and return to the previous step.
397 self.data.swap(parent_idx, index);
398 index = parent_idx;
399
400 changed = true;
401 }
402
403 changed
404 }
405
406 /// Ensures that elements are in the correct order, starting from a given parent node,
407 /// working its way down the heap.
408 ///
409 /// ## Returns
410 ///
411 /// Returns `true` if the tree was changed or `false` if no change was performed.
412 fn downheap(&mut self, mut index: usize) -> bool
413 where
414 T: PartialOrd,
415 H: HeapProperty<T>,
416 {
417 debug_assert!(index < self.data.len());
418 let mut changed = false;
419
420 // Compare the new root with its children; if they are in the correct order, stop.
421 // If not, swap the element with one of its children and return to the previous step.
422 // (Swap with its smaller child in a min-heap and its larger child in a max-heap.)
423 loop {
424 let left_child_idx = self.get_left_child_idx(index);
425 let right_child_idx = self.get_right_child_idx(index);
426
427 let current = &self.data[index];
428
429 match (left_child_idx, right_child_idx) {
430 (Some(left), Some(right)) => {
431 let left_child = &self.data[left];
432 let right_child = &self.data[right];
433
434 if H::property_upheld(¤t, left_child)
435 && H::property_upheld(current, right_child)
436 {
437 break;
438 }
439
440 if H::property_upheld(left_child, right_child) {
441 self.data.swap(index, left);
442 index = left;
443 } else {
444 self.data.swap(index, right);
445 index = right;
446 }
447
448 changed = true;
449 }
450 (Some(child), None) => {
451 let left_child = &self.data[child];
452
453 if H::property_upheld(current, left_child) {
454 break;
455 }
456
457 self.data.swap(index, child);
458
459 // Since there is no right child and the tree is balanced, the left child can also not have any children.
460 debug_assert!(self.get_left_child_idx(child).is_none());
461
462 changed = true;
463 }
464 (None, Some(_)) => unreachable!("the tree cannot have only a right child"),
465 (None, None) => break,
466 }
467 }
468
469 changed
470 }
471
472 /// Gets the index of the left child of the item at the specified `index`.
473 const fn get_left_child_idx_unchecked(index: usize) -> usize {
474 2 * index + 1
475 }
476
477 /// Gets the index of the left child of the item at the specified `index`.
478 ///
479 /// ## Returns
480 ///
481 /// * `Some(index)` if the element exists in the tree.
482 /// * `None` if the child does not exist.
483 fn get_left_child_idx(&self, index: usize) -> Option<usize> {
484 let idx = Self::get_left_child_idx_unchecked(index);
485 if idx < self.data.len() {
486 Some(idx)
487 } else {
488 None
489 }
490 }
491
492 /// Gets the index of the right child of the item at the specified `index`.
493 const fn get_right_child_idx_unchecked(index: usize) -> usize {
494 2 * index + 2
495 }
496
497 /// Gets the index of the right child of the item at the specified `index`.
498 ///
499 /// ## Returns
500 ///
501 /// * `Some(index)` if the element exists in the tree.
502 /// * `None` if the child does not exist.
503 fn get_right_child_idx(&self, index: usize) -> Option<usize> {
504 let idx = Self::get_right_child_idx_unchecked(index);
505 if idx < self.data.len() {
506 Some(idx)
507 } else {
508 None
509 }
510 }
511
512 /// Gets the index of the parent of the item at the specified `index`.
513 ///
514 /// ## Returns
515 ///
516 /// * `Some(index)` if the element exists in the tree.
517 /// * `None` if the parent does not exist.
518 fn get_parent_idx(&self, index: usize) -> Option<usize> {
519 if index == 0 || index >= self.data.len() {
520 return None;
521 }
522
523 Some((index - 1) / 2)
524 }
525}
526
527impl<T, H> FromIterator<T> for BinaryHeap<T, H>
528where
529 T: PartialOrd,
530 H: HeapProperty<T>,
531{
532 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
533 <Self as From<Vec<T>>>::from(iter.into_iter().collect())
534 }
535}
536
537impl<T, H> From<Vec<T>> for BinaryHeap<T, H>
538where
539 T: PartialOrd,
540 H: HeapProperty<T>,
541{
542 fn from(value: Vec<T>) -> Self {
543 let mut tree = Self {
544 data: value,
545 _heap_property: PhantomData,
546 };
547
548 // Floyd's method.
549 let length = tree.data.len();
550 for i in (0..=(length / 2)).rev() {
551 tree.downheap(i);
552 }
553
554 tree
555 }
556}
557
558impl<T, H> Debug for BinaryHeap<T, H>
559where
560 T: Debug,
561 H: HeapProperty<T>,
562{
563 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
564 f.debug_struct(&format!("Binary{}Heap", H::NAME))
565 .field("data", &self.data)
566 .finish()
567 }
568}
569
570impl<T, H> Default for BinaryHeap<T, H> {
571 fn default() -> Self {
572 Self::new()
573 }
574}
575
576impl<T, H> Clone for BinaryHeap<T, H>
577where
578 T: Clone,
579{
580 fn clone(&self) -> Self {
581 Self {
582 data: self.data.clone(),
583 _heap_property: PhantomData,
584 }
585 }
586}
587
588impl<T, H> AsRef<[T]> for BinaryHeap<T, H> {
589 fn as_ref(&self) -> &[T] {
590 &self.data
591 }
592}
593
594impl<T> HeapProperty<T> for Max<T>
595where
596 T: PartialOrd,
597{
598 const NAME: &'static str = "Max";
599
600 fn property_upheld(lhs: &T, rhs: &T) -> bool {
601 lhs >= rhs
602 }
603}
604
605impl<T> HeapProperty<T> for Min<T>
606where
607 T: PartialOrd,
608{
609 const NAME: &'static str = "Min";
610
611 fn property_upheld(lhs: &T, rhs: &T) -> bool {
612 lhs <= rhs
613 }
614}