Skip to content

Commit 4e4ae64

Browse files
teskjeEmilien Fugier
authored andcommitted
Add a heap sort implementation (#27)
* Add a heap sort implementation.
1 parent 2144a48 commit 4e4ae64

File tree

2 files changed

+127
-0
lines changed

2 files changed

+127
-0
lines changed

src/sorting/heap_sort.rs

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/// Sort a mutable slice using heap sort.
2+
///
3+
/// Heap sort is an in-place O(n log n) sorting algorithm. It is based on a
4+
/// max heap, a binary tree data structure whose main feature is that
5+
/// parent nodes are always greater or equal to their child nodes.
6+
///
7+
/// # Max Heap Implementation
8+
///
9+
/// A max heap can be efficiently implemented with an array.
10+
/// For example, the binary tree:
11+
/// ```text
12+
/// 1
13+
/// 2 3
14+
/// 4 5 6 7
15+
/// ```
16+
///
17+
/// ... is represented by the following array:
18+
/// ```text
19+
/// 1 23 4567
20+
/// ```
21+
///
22+
/// Given the index `i` of a node, parent and child indices can be calculated
23+
/// as follows:
24+
/// ```text
25+
/// parent(i) = (i-1) / 2
26+
/// left_child(i) = 2*i + 1
27+
/// right_child(i) = 2*i + 2
28+
/// ```
29+
30+
/// # Algorithm
31+
///
32+
/// Heap sort has two steps:
33+
/// 1. Convert the input array to a max heap.
34+
/// 2. Partition the array into heap part and sorted part. Initially the
35+
/// heap consists of the whole array and the sorted part is empty:
36+
/// ```text
37+
/// arr: [ heap |]
38+
/// ```
39+
///
40+
/// Repeatedly swap the root (i.e. the largest) element of the heap with
41+
/// the last element of the heap and increase the sorted part by one:
42+
/// ```text
43+
/// arr: [ root ... last | sorted ]
44+
/// --> [ last ... | root sorted ]
45+
/// ```
46+
///
47+
/// After each swap, fix the heap to make it a valid max heap again.
48+
/// Once the heap is empty, `arr` is completely sorted.
49+
pub fn heap_sort<T: Ord>(arr: &mut [T]) {
50+
if arr.len() <= 1 {
51+
return; // already sorted
52+
}
53+
54+
heapify(arr);
55+
56+
for end in (1..arr.len()).rev() {
57+
arr.swap(0, end);
58+
move_down(&mut arr[..end], 0);
59+
}
60+
}
61+
62+
/// Convert `arr` into a max heap.
63+
fn heapify<T: Ord>(arr: &mut [T]) {
64+
let last_parent = (arr.len() - 2) / 2;
65+
for i in (0..last_parent + 1).rev() {
66+
move_down(arr, i);
67+
}
68+
}
69+
70+
/// Move the element at `root` down until `arr` is a max heap again.
71+
///
72+
/// This assumes that the subtrees under `root` are valid max heaps already.
73+
fn move_down<T: Ord>(arr: &mut [T], mut root: usize) {
74+
let last = arr.len() - 1;
75+
loop {
76+
let left = 2 * root + 1;
77+
if left > last {
78+
break;
79+
}
80+
let right = left + 1;
81+
let max = if right <= last && arr[right] > arr[left] {
82+
right
83+
} else {
84+
left
85+
};
86+
87+
if arr[max] > arr[root] {
88+
arr.swap(root, max);
89+
}
90+
root = max;
91+
}
92+
}
93+
94+
#[cfg(test)]
95+
mod tests {
96+
use super::*;
97+
98+
#[test]
99+
fn empty() {
100+
let mut arr: Vec<i32> = Vec::new();
101+
heap_sort(&mut arr);
102+
assert_eq!(&arr, &[]);
103+
}
104+
105+
#[test]
106+
fn single_element() {
107+
let mut arr = vec![1];
108+
heap_sort(&mut arr);
109+
assert_eq!(&arr, &[1]);
110+
}
111+
112+
#[test]
113+
fn sorted_array() {
114+
let mut arr = vec![1, 2, 3, 4];
115+
heap_sort(&mut arr);
116+
assert_eq!(&arr, &[1, 2, 3, 4]);
117+
}
118+
119+
#[test]
120+
fn unsorted_array() {
121+
let mut arr = vec![3, 4, 2, 1];
122+
heap_sort(&mut arr);
123+
assert_eq!(&arr, &[1, 2, 3, 4]);
124+
}
125+
}

src/sorting/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
mod bubble_sort;
22
mod counting_sort;
3+
mod heap_sort;
34
mod insertion;
45
mod quick_sort;
56

67
pub use self::bubble_sort::bubble_sort;
78
pub use self::counting_sort::counting_sort;
89
pub use self::counting_sort::generic_counting_sort;
10+
pub use self::heap_sort::heap_sort;
911
pub use self::insertion::insertion_sort;
1012
pub use self::quick_sort::quick_sort;

0 commit comments

Comments
 (0)