Skip to content

Commit 2f5d022

Browse files
committed
MinHeap utility class
1 parent 60f42cb commit 2f5d022

File tree

3 files changed

+74
-33
lines changed

3 files changed

+74
-33
lines changed

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ pub mod util {
148148
pub mod ansi;
149149
pub mod grid;
150150
pub mod hash;
151+
pub mod heap;
151152
pub mod integer;
152153
pub mod iter;
153154
pub mod math;

src/util/heap.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
//! [Min heap] more suitable for algorithms such as [Dijkstra] and [A*] than Rust's default
2+
//! max heap. Splits the sorting key and value, so that you can order items without having
3+
//! to implement [`Ord`] on the value type.
4+
//!
5+
//! [Min heap]: https://en.wikipedia.org/wiki/Heap_(data_structure)
6+
//! [Dijkstra]: https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm
7+
//! [A*]: https://en.wikipedia.org/wiki/A*_search_algorithm
8+
use std::cmp::Ordering;
9+
use std::collections::BinaryHeap;
10+
11+
struct Wrapper<K: Ord, V> {
12+
key: K,
13+
value: V,
14+
}
15+
16+
impl<K: Ord, V> PartialEq for Wrapper<K, V> {
17+
#[inline]
18+
fn eq(&self, other: &Self) -> bool {
19+
self.key == other.key
20+
}
21+
}
22+
23+
impl<K: Ord, V> Eq for Wrapper<K, V> {}
24+
25+
impl<K: Ord, V> PartialOrd for Wrapper<K, V> {
26+
#[inline]
27+
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
28+
Some(self.cmp(other))
29+
}
30+
}
31+
32+
impl<K: Ord, V> Ord for Wrapper<K, V> {
33+
#[inline]
34+
fn cmp(&self, other: &Self) -> Ordering {
35+
other.key.cmp(&self.key)
36+
}
37+
}
38+
39+
#[derive(Default)]
40+
pub struct MinHeap<K: Ord, V> {
41+
heap: BinaryHeap<Wrapper<K, V>>,
42+
}
43+
44+
impl<K: Ord, V> MinHeap<K, V> {
45+
pub fn new() -> Self {
46+
MinHeap { heap: BinaryHeap::new() }
47+
}
48+
49+
pub fn with_capacity(capacity: usize) -> Self {
50+
MinHeap { heap: BinaryHeap::with_capacity(capacity) }
51+
}
52+
53+
#[inline]
54+
pub fn push(&mut self, key: K, value: V) {
55+
self.heap.push(Wrapper { key, value });
56+
}
57+
58+
#[inline]
59+
pub fn pop(&mut self) -> Option<(K, V)> {
60+
self.heap.pop().map(|w| (w.key, w.value))
61+
}
62+
}

src/year2021/day23.rs

Lines changed: 11 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use crate::util::hash::*;
2+
use crate::util::heap::*;
23
use std::array::from_fn;
3-
use std::cmp::Ordering;
4-
use std::collections::BinaryHeap;
54
use std::hash::*;
65

76
const A: usize = 0;
@@ -88,26 +87,6 @@ impl Burrow {
8887
}
8988
}
9089

91-
#[derive(Copy, Clone, PartialEq, Eq)]
92-
struct State {
93-
burrow: Burrow,
94-
energy: usize,
95-
}
96-
97-
impl PartialOrd for State {
98-
#[inline]
99-
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
100-
Some(self.cmp(other))
101-
}
102-
}
103-
104-
impl Ord for State {
105-
#[inline]
106-
fn cmp(&self, other: &Self) -> Ordering {
107-
other.energy.cmp(&self.energy)
108-
}
109-
}
110-
11190
pub fn parse(input: &str) -> Vec<Vec<usize>> {
11291
input
11392
.lines()
@@ -136,13 +115,12 @@ pub fn part2(input: &[Vec<usize>]) -> usize {
136115
}
137116

138117
fn organize(burrow: Burrow) -> usize {
139-
let mut todo = BinaryHeap::with_capacity(20_000);
118+
let mut todo = MinHeap::with_capacity(20_000);
140119
let mut seen = FastMap::with_capacity(20_000);
141120

142-
todo.push(State { burrow, energy: best_possible(&burrow) });
121+
todo.push(best_possible(&burrow), burrow);
143122

144-
while let Some(state) = todo.pop() {
145-
let State { mut burrow, energy } = state;
123+
while let Some((energy, mut burrow)) = todo.pop() {
146124
let open: [bool; 4] = from_fn(|i| burrow.rooms[i].open(i));
147125

148126
let mut changed = false;
@@ -164,7 +142,7 @@ fn organize(burrow: Burrow) -> usize {
164142
// Moving back to home burrow does not change cost
165143
let min = seen.get(&burrow).unwrap_or(&usize::MAX);
166144
if energy < *min {
167-
todo.push(State { burrow, energy });
145+
todo.push(energy, burrow);
168146
seen.insert(burrow, energy);
169147
}
170148
} else {
@@ -173,8 +151,8 @@ fn organize(burrow: Burrow) -> usize {
173151
let offset = 2 + 2 * i;
174152
let forward = (offset + 1)..11;
175153
let reverse = (0..offset).rev();
176-
expand(&mut todo, &mut seen, &state, i, forward);
177-
expand(&mut todo, &mut seen, &state, i, reverse);
154+
expand(&mut todo, &mut seen, burrow, energy, i, forward);
155+
expand(&mut todo, &mut seen, burrow, energy, i, reverse);
178156
}
179157
}
180158
}
@@ -240,13 +218,13 @@ fn condense(burrow: &mut Burrow, kind: usize, iter: impl Iterator<Item = usize>)
240218
}
241219

242220
fn expand(
243-
todo: &mut BinaryHeap<State>,
221+
todo: &mut MinHeap<usize, Burrow>,
244222
seen: &mut FastMap<Burrow, usize>,
245-
state: &State,
223+
mut burrow: Burrow,
224+
energy: usize,
246225
room_index: usize,
247226
iter: impl Iterator<Item = usize>,
248227
) {
249-
let State { mut burrow, energy } = state;
250228
let kind = burrow.rooms[room_index].pop();
251229

252230
for hallway_index in iter {
@@ -290,7 +268,7 @@ fn expand(
290268
let min = seen.get(&next).unwrap_or(&usize::MAX);
291269

292270
if next_energy < *min {
293-
todo.push(State { burrow: next, energy: next_energy });
271+
todo.push(next_energy, next);
294272
seen.insert(next, next_energy);
295273
}
296274
}

0 commit comments

Comments
 (0)