make dijkstra generic
breaks 81
This commit is contained in:
+45
-68
@@ -6,34 +6,41 @@ type Coordinate = (usize, usize);
|
||||
|
||||
const START: Coordinate = (0, 0);
|
||||
|
||||
pub trait MatrixInner<T>
|
||||
pub trait Matrix<T>
|
||||
where
|
||||
T: Add + PartialOrd + Debug + Copy,
|
||||
{
|
||||
fn height(&self) -> usize;
|
||||
fn width(&self) -> usize;
|
||||
fn get(&self, coordinate: &Coordinate) -> &Option<Node<T>>;
|
||||
fn get_mut(&mut self, coordinate: &Coordinate) -> &mut Option<Node<T>>;
|
||||
fn get(&self, coordinate: Coordinate) -> Option<&dyn Node<T>>;
|
||||
fn get_mut(&mut self, coordinate: Coordinate) -> Option<&mut dyn Node<T>>;
|
||||
}
|
||||
|
||||
pub trait Matrix<T>: MatrixInner<T> + Debug
|
||||
where
|
||||
T: Add + PartialOrd + Debug + Copy,
|
||||
{
|
||||
impl<T> Debug for dyn Matrix<T> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Dijkstra<T> {
|
||||
matrix: Box<dyn Matrix<T>>,
|
||||
pub struct Dijkstra<'a, T> {
|
||||
matrix: Box<&'a mut dyn Matrix<T>>,
|
||||
unvisited: HashSet<Coordinate>,
|
||||
}
|
||||
|
||||
impl<T> Dijkstra<T>
|
||||
impl<'a, T> Debug for Dijkstra<'a, T> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("Dijkstra")
|
||||
.field("unvisited", &self.unvisited)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Dijkstra<'a, T>
|
||||
where
|
||||
T: PartialOrd + Add<Output = T> + Display + Copy + Debug,
|
||||
{
|
||||
pub fn new(matrix: Box<dyn Matrix<T>>) -> Self {
|
||||
let unvisited = Self::initialize_unvisited_set(&*matrix, START);
|
||||
pub fn new(matrix: Box<&'a mut dyn Matrix<T>>) -> Self {
|
||||
let unvisited = Self::initialize_unvisited_set(*matrix, START);
|
||||
Self { matrix, unvisited }
|
||||
}
|
||||
|
||||
@@ -41,14 +48,7 @@ where
|
||||
while !self.unvisited.is_empty() {
|
||||
let coord = self.get_unvisited_coord_with_smallest_distance_from_start();
|
||||
let neighbours = self.get_neighbours(&coord);
|
||||
let previous_distance = *self
|
||||
.matrix
|
||||
.get(&coord)
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.distance
|
||||
.as_ref()
|
||||
.unwrap();
|
||||
let previous_distance = *self.matrix.get(coord).unwrap().get_distance().unwrap();
|
||||
for neighbour in neighbours {
|
||||
self.update_neighbour(neighbour, coord, previous_distance);
|
||||
}
|
||||
@@ -60,8 +60,8 @@ where
|
||||
.unvisited
|
||||
.iter()
|
||||
.filter_map(|c| {
|
||||
let node = self.matrix.get(c).as_ref().unwrap();
|
||||
node.distance.map(|value| (c, value))
|
||||
let node = self.matrix.get(*c).unwrap();
|
||||
node.get_distance().map(|value| (c, value))
|
||||
})
|
||||
.reduce(|(c0, v0), (c1, v1)| if v0 < v1 { (c0, v0) } else { (c1, v1) })
|
||||
.map(|(c, _)| *c)
|
||||
@@ -83,34 +83,17 @@ where
|
||||
}
|
||||
|
||||
fn update_neighbour(&mut self, next: Coordinate, previous: Coordinate, previous_distance: T) {
|
||||
let mut next_node = self.matrix.get_mut(&next).as_mut().unwrap();
|
||||
let new_distance = previous_distance + next_node.value;
|
||||
match next_node.distance {
|
||||
None => {
|
||||
next_node.distance = Some(new_distance);
|
||||
next_node.previous = Some(previous);
|
||||
}
|
||||
Some(old_distance) => {
|
||||
if new_distance < old_distance {
|
||||
next_node.distance = Some(new_distance);
|
||||
next_node.previous = Some(previous);
|
||||
}
|
||||
let next_node = self.matrix.get_mut(next).unwrap();
|
||||
let new_distance = previous_distance + *next_node.get_value();
|
||||
if let Some(old_distance) = next_node.get_distance() {
|
||||
if new_distance < *old_distance {
|
||||
Self::update_node(next_node, new_distance, previous);
|
||||
}
|
||||
} else {
|
||||
Self::update_node(next_node, new_distance, previous);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn show(&self) {
|
||||
let result = self
|
||||
.matrix
|
||||
.get(&(self.matrix.height() - 1, self.matrix.width() - 1))
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.distance
|
||||
.as_ref()
|
||||
.unwrap();
|
||||
println!("{}", result);
|
||||
}
|
||||
|
||||
fn initialize_unvisited_set(matrix: &dyn Matrix<T>, start: Coordinate) -> HashSet<Coordinate> {
|
||||
let unvisited: HashSet<_> = (0..matrix.height())
|
||||
.flat_map(|x| (0..matrix.width()).zip([x].into_iter().cycle()))
|
||||
@@ -118,27 +101,21 @@ where
|
||||
.collect();
|
||||
unvisited
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Hash, Debug)]
|
||||
pub struct Node<T>
|
||||
where
|
||||
T: Add + PartialOrd,
|
||||
{
|
||||
value: T,
|
||||
distance: Option<T>,
|
||||
previous: Option<Coordinate>,
|
||||
}
|
||||
|
||||
impl<T> From<T> for Node<T>
|
||||
where
|
||||
T: Add + PartialOrd,
|
||||
{
|
||||
fn from(value: T) -> Self {
|
||||
Node {
|
||||
value,
|
||||
distance: None,
|
||||
previous: None,
|
||||
}
|
||||
fn update_node(next_node: &mut dyn Node<T>, new_distance: T, previous: (usize, usize)) {
|
||||
next_node.set_distance(new_distance);
|
||||
next_node.set_previous(previous);
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Node<T>
|
||||
where
|
||||
T: Add + PartialOrd,
|
||||
{
|
||||
fn get_value(&self) -> &T;
|
||||
fn get_distance(&self) -> Option<&T>;
|
||||
fn get_previous(&self) -> Option<Coordinate>;
|
||||
|
||||
fn set_distance(&mut self, distance: T);
|
||||
fn set_previous(&mut self, coord: Coordinate);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user