Skip to content

Commit b0c938c

Browse files
committed
add binary heap
1 parent 87ecfda commit b0c938c

File tree

2 files changed

+151
-1
lines changed

2 files changed

+151
-1
lines changed

src/binary_heap.rs

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
2+
use std::cmp::Ordering;
3+
4+
struct BinaryHeap<T, I> {
5+
data: Vec<T>,
6+
comparator: I
7+
}
8+
9+
#[inline] fn parent(i: usize) -> usize { (i - 1) / 2 }
10+
#[inline] fn left_child(i: usize) -> usize { i * 2 + 1 }
11+
12+
type DefaultCmp<T> = fn(&T, &T) -> Ordering;
13+
impl<T: Ord> BinaryHeap<T, DefaultCmp<T>> {
14+
fn comparator(a: &T, b: &T) -> Ordering {
15+
a.cmp(b)
16+
}
17+
fn from(data: Vec<T>) -> BinaryHeap<T, DefaultCmp<T>> {
18+
let mut ans = BinaryHeap {
19+
data,
20+
comparator: Self::comparator as DefaultCmp<T>,
21+
};
22+
ans.build_heap();
23+
ans
24+
}
25+
fn new() -> BinaryHeap<T, DefaultCmp<T>> {
26+
fn comparator<T: Ord>(a: &T, b: &T) -> Ordering {
27+
a.cmp(b)
28+
}
29+
BinaryHeap {
30+
data: vec![],
31+
comparator: Self::comparator as DefaultCmp<T>,
32+
}
33+
}
34+
}
35+
36+
impl<T, I> BinaryHeap<T, I> where I: FnMut(&T, &T) -> Ordering {
37+
fn with_comparator(comparator: I) -> BinaryHeap<T, I> {
38+
BinaryHeap {
39+
data: vec![],
40+
comparator,
41+
}
42+
}
43+
44+
fn from_with_comparator(data: Vec<T>, comparator: I) -> BinaryHeap<T, I> {
45+
let mut ans = BinaryHeap {
46+
data,
47+
comparator,
48+
};
49+
ans.build_heap();
50+
ans
51+
}
52+
53+
fn is_empty(&self) -> bool {
54+
self.data.is_empty()
55+
}
56+
57+
fn len(&self) -> usize {
58+
self.data.len()
59+
}
60+
61+
fn build_heap(&mut self) {
62+
if self.len() < 2 { return; }
63+
// if x is last internal index, then 2x+1 == self.len() - 1
64+
// x = (self.len() - 2) / 2;
65+
let last_internal = (self.len() - 2) / 2;
66+
for i in (0..=last_internal).rev() {
67+
self.sift_down(i);
68+
}
69+
}
70+
71+
#[inline]
72+
fn is_less(&mut self, i: usize, j: usize) -> bool {
73+
(self.comparator)(&self.data[i], &self.data[j]) == Ordering::Less
74+
}
75+
76+
fn sift_up(&mut self, mut i: usize) {
77+
// if a value > its parent
78+
while i != 0 {
79+
let parent_i = parent(i);
80+
if self.is_less(parent_i, i) {
81+
self.data.swap(parent_i, i);
82+
i = parent_i;
83+
} else {
84+
break;
85+
}
86+
}
87+
}
88+
89+
fn sift_down(&mut self, mut i: usize) {
90+
// if a value < max of its child
91+
loop {
92+
let lc_i = left_child(i);
93+
if !self.contains_idx(lc_i) { break; } // has no left child
94+
let mut max_idx = if self.is_less(i, lc_i) { lc_i } else { i };
95+
let rc_i = lc_i + 1;
96+
if self.contains_idx(rc_i) && self.is_less(max_idx, rc_i) {
97+
max_idx = rc_i;
98+
}
99+
if max_idx == i { break; } // value >= max of its child
100+
self.data.swap(i, max_idx);
101+
i = max_idx;
102+
}
103+
}
104+
105+
#[inline]
106+
fn contains_idx(&self, i: usize) -> bool {
107+
i < self.data.len()
108+
}
109+
110+
fn push(&mut self, v: T) {
111+
self.data.push(v);
112+
self.sift_up(self.data.len() - 1);
113+
}
114+
115+
fn pop(&mut self) -> Option<T> {
116+
if self.data.is_empty() {
117+
return None;
118+
}
119+
let ans = self.data.swap_remove(0);
120+
self.sift_down(0);
121+
Some(ans)
122+
}
123+
}
124+
125+
#[cfg(test)]
126+
mod tests {
127+
128+
use super::*;
129+
130+
#[test]
131+
fn test_basic_pq() {
132+
let mut pq: BinaryHeap<i32, _> = BinaryHeap::from_with_comparator(
133+
vec![2,1,6,3,9,7,4,8,5],
134+
|a, b| a.cmp(b)
135+
);
136+
for i in (1..=9).rev() {
137+
assert_eq!(Some(i), pq.pop());
138+
}
139+
assert_eq!(None, pq.pop());
140+
}
141+
142+
#[test]
143+
fn test_default_cmp() {
144+
let mut pq: BinaryHeap<i32, _> = BinaryHeap::from(vec![2,1,6,3,9,7,4,8,5]);
145+
for i in (1..=9).rev() {
146+
assert_eq!(Some(i), pq.pop());
147+
}
148+
assert_eq!(None, pq.pop());
149+
}
150+
}

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
pub mod string;
2-
2+
pub mod binary_heap;

0 commit comments

Comments
 (0)