Initial release #1

Merged
warrence merged 102 commits from dev into main 2026-06-30 10:26:52 +02:00
Showing only changes of commit 2a35c47ad4 - Show all commits
+115 -2
View File
@@ -1,3 +1,6 @@
use std::cmp::Ordering;
use std::collections::BinaryHeap;
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
struct Vertex(usize);
@@ -74,6 +77,70 @@ impl Graph {
}
}
#[derive(PartialEq, Eq)]
struct DistanceOrderedVertex {
distance: u32,
vertex: Vertex,
}
impl PartialOrd for DistanceOrderedVertex {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.distance.cmp(&other.distance))
}
}
impl Ord for DistanceOrderedVertex {
fn cmp(&self, other: &Self) -> Ordering {
other.distance.cmp(&self.distance)
}
}
// TODO: Maybe introduce a return struct type for Dijkstra's algorithm?
fn dijkstra(graph: &Graph, source: Vertex) -> (Vec<Option<u32>>, Vec<Option<Vertex>>) {
let mut distances = vec![None; graph.vertex_count()];
let mut predecessors = vec![None; graph.vertex_count()];
let mut heap = BinaryHeap::new();
distances[source.0] = Some(0);
heap.push(DistanceOrderedVertex {
vertex: source,
distance: 0,
});
while let Some(v) = heap.pop() {
// TODO: Simplify with a neighbor iterator.
// Finds the first neighbor of v.
let Some(mut incidence) = graph.incidence_headers[v.vertex.0].first_incidence else {
break;
};
loop {
// Processes one neighbor of v.
let neighbor = graph.incidence_vertices[incidence.0];
// TODO: Add a way to provide custom edge weights for Dijkstra's algorithm.
let edge_weight = 1;
let new_distance = distances[v.vertex.0].unwrap() + edge_weight;
if match distances[neighbor.0] {
None => true,
Some(old_distance) if old_distance > new_distance => true,
_ => false,
} {
distances[neighbor.0] = Some(new_distance);
predecessors[neighbor.0] = Some(v.vertex);
heap.push(DistanceOrderedVertex {
vertex: neighbor,
distance: new_distance,
});
}
// Finds next neighbor of v.
let Some(next) = graph.next_incidences[incidence.0] else {
break;
};
incidence = next;
}
}
(distances, predecessors)
}
fn main() {
// TODO: Move this graph example into one or more tests.
let mut graph = Graph {
@@ -154,6 +221,52 @@ fn main() {
);
}
// TODO: test Dijkstra's algorithm starting at 0 and at another vertex.
let expected_distances_to_v0 = [0, 1, 2, 2, 2, 3, 3, 3, 3, 4];
let (distances, predecessors) = dijkstra(&graph, vertices[0]);
let expected_distances_from_v0 = [
Some(0),
Some(1),
Some(2),
Some(2),
Some(2),
Some(3),
Some(3),
Some(3),
Some(3),
Some(4),
];
let expected_predecessors_from_v0 = [
vec![None],
vec![Some(vertices[0])],
vec![Some(vertices[1])],
vec![Some(vertices[1])],
vec![Some(vertices[1])],
vec![Some(vertices[2])],
vec![Some(vertices[2]), Some(vertices[3])],
vec![Some(vertices[4])],
vec![Some(vertices[4])],
vec![Some(vertices[5]), Some(vertices[6]), Some(vertices[7])],
];
assert_eq!(
distances.len(),
graph.vertex_count(),
"distances count from Dijkstra's algorithm must equal vertex count"
);
assert_eq!(
predecessors.len(),
graph.vertex_count(),
"predecessors count from Dijkstra's algorithm must equal vertex count"
);
for i in 0..graph.vertex_count() {
assert_eq!(
distances[i], expected_distances_from_v0[i],
"unexpected distance from {:?} to {:?} from Dijkstra's algorithm",
vertices[0], vertices[i]
);
assert!(
expected_predecessors_from_v0[i].contains(&predecessors[i]),
"unexpected predecessor {:?} of {:?} from Dijkstra's algorithm",
predecessors[i],
vertices[i]
);
}
}