-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
/
Copy pathheap_sort.rs
114 lines (100 loc) · 3.52 KB
/
heap_sort.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
//! This module provides functions for heap sort algorithm.
use std::cmp::Ordering;
/// Builds a heap from the provided array.
///
/// This function builds either a max heap or a min heap based on the `is_max_heap` parameter.
///
/// # Arguments
///
/// * `arr` - A mutable reference to the array to be sorted.
/// * `is_max_heap` - A boolean indicating whether to build a max heap (`true`) or a min heap (`false`).
fn build_heap<T: Ord>(arr: &mut [T], is_max_heap: bool) {
let mut i = (arr.len() - 1) / 2;
while i > 0 {
heapify(arr, i, is_max_heap);
i -= 1;
}
heapify(arr, 0, is_max_heap);
}
/// Fixes a heap violation starting at the given index.
///
/// This function adjusts the heap rooted at index `i` to fix the heap property violation.
/// It assumes that the subtrees rooted at left and right children of `i` are already heaps.
///
/// # Arguments
///
/// * `arr` - A mutable reference to the array representing the heap.
/// * `i` - The index to start fixing the heap violation.
/// * `is_max_heap` - A boolean indicating whether to maintain a max heap or a min heap.
fn heapify<T: Ord>(arr: &mut [T], i: usize, is_max_heap: bool) {
let comparator: fn(&T, &T) -> Ordering = if !is_max_heap {
|a, b| b.cmp(a)
} else {
|a, b| a.cmp(b)
};
let mut idx = i;
let l = 2 * i + 1;
let r = 2 * i + 2;
if l < arr.len() && comparator(&arr[l], &arr[idx]) == Ordering::Greater {
idx = l;
}
if r < arr.len() && comparator(&arr[r], &arr[idx]) == Ordering::Greater {
idx = r;
}
if idx != i {
arr.swap(i, idx);
heapify(arr, idx, is_max_heap);
}
}
/// Sorts the given array using heap sort algorithm.
///
/// This function sorts the array either in ascending or descending order based on the `ascending` parameter.
///
/// # Arguments
///
/// * `arr` - A mutable reference to the array to be sorted.
/// * `ascending` - A boolean indicating whether to sort in ascending order (`true`) or descending order (`false`).
pub fn heap_sort<T: Ord>(arr: &mut [T], ascending: bool) {
if arr.len() <= 1 {
return;
}
// Build heap based on the order
build_heap(arr, ascending);
let mut end = arr.len() - 1;
while end > 0 {
arr.swap(0, end);
heapify(&mut arr[..end], 0, ascending);
end -= 1;
}
}
#[cfg(test)]
mod tests {
use crate::sorting::{have_same_elements, heap_sort, is_descending_sorted, is_sorted};
macro_rules! test_heap_sort {
($($name:ident: $input:expr,)*) => {
$(
#[test]
fn $name() {
let input_array = $input;
let mut arr_asc = input_array.clone();
heap_sort(&mut arr_asc, true);
assert!(is_sorted(&arr_asc) && have_same_elements(&arr_asc, &input_array));
let mut arr_dsc = input_array.clone();
heap_sort(&mut arr_dsc, false);
assert!(is_descending_sorted(&arr_dsc) && have_same_elements(&arr_dsc, &input_array));
}
)*
}
}
test_heap_sort! {
empty_array: Vec::<i32>::new(),
single_element_array: vec![5],
sorted: vec![1, 2, 3, 4, 5],
sorted_desc: vec![5, 4, 3, 2, 1, 0],
basic_0: vec![9, 8, 7, 6, 5],
basic_1: vec![8, 3, 1, 5, 7],
basic_2: vec![4, 5, 7, 1, 2, 3, 2, 8, 5, 4, 9, 9, 100, 1, 2, 3, 6, 4, 3],
duplicated_elements: vec![5, 5, 5, 5, 5],
strings: vec!["aa", "a", "ba", "ab"],
}
}