Use PriorityQueue for Dijkstra's, requires Hash for Vertex
This commit is contained in:
@@ -11,4 +11,5 @@ keywords = ["graph", "graph-algorithms"]
|
|||||||
categories = ["algorithms", "data-structures", "mathematics"]
|
categories = ["algorithms", "data-structures", "mathematics"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
priority-queue = "2.7.0"
|
||||||
typed-generational-arena = "0.2.9"
|
typed-generational-arena = "0.2.9"
|
||||||
|
|||||||
+25
-34
@@ -28,30 +28,14 @@
|
|||||||
//! [Depth-first search]: https://en.wikipedia.org/wiki/Depth-first_search
|
//! [Depth-first search]: https://en.wikipedia.org/wiki/Depth-first_search
|
||||||
//! [Dijkstra's algorithm]: https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm
|
//! [Dijkstra's algorithm]: https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm
|
||||||
|
|
||||||
use std::cmp::Ordering;
|
use priority_queue::PriorityQueue;
|
||||||
use std::collections::{BinaryHeap, VecDeque};
|
use std::cmp::Reverse;
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
use std::hash::Hash;
|
||||||
|
|
||||||
use crate::maps::EntityMap;
|
use crate::maps::EntityMap;
|
||||||
use crate::traits::{GraphTopology, IncidenceCursor};
|
use crate::traits::{GraphTopology, IncidenceCursor};
|
||||||
|
|
||||||
#[derive(PartialEq, Eq)]
|
|
||||||
struct DistanceOrderedVertex<V> {
|
|
||||||
distance: u32,
|
|
||||||
vertex: V,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<V: Eq> PartialOrd for DistanceOrderedVertex<V> {
|
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
|
||||||
Some(self.cmp(other))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<V: Eq> Ord for DistanceOrderedVertex<V> {
|
|
||||||
fn cmp(&self, other: &Self) -> Ordering {
|
|
||||||
other.distance.cmp(&self.distance)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return data type for [`dijkstra`] and [`dijkstra_unweighted`].
|
/// Return data type for [`dijkstra`] and [`dijkstra_unweighted`].
|
||||||
pub struct DijkstraResult<V: Copy> {
|
pub struct DijkstraResult<V: Copy> {
|
||||||
/// Vertex map of minimum distances from a given `source` vertex.
|
/// Vertex map of minimum distances from a given `source` vertex.
|
||||||
@@ -61,7 +45,7 @@ pub struct DijkstraResult<V: Copy> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Generalize the return type of the weight function.
|
// TODO: Generalize the return type of the weight function.
|
||||||
// TODO: Add complexity information for Dijkstra's algorithm variants.
|
// TODO: A Fibonacci heap would lower complexity to O(|E| + |V| log |V|) by making decrease-key O(1) amortized instead of O(log |V|). No standard Rust implementation exists; high constant factors may negate the asymptotic gain in practice.
|
||||||
/// [Dijkstra's algorithm] with custom edge weights, returns minimum distances and predecessors.
|
/// [Dijkstra's algorithm] with custom edge weights, returns minimum distances and predecessors.
|
||||||
///
|
///
|
||||||
/// Calculates the shortest paths from `source` to all vertices in `graph` with edge weights given
|
/// Calculates the shortest paths from `source` to all vertices in `graph` with edge weights given
|
||||||
@@ -69,6 +53,8 @@ pub struct DijkstraResult<V: Copy> {
|
|||||||
/// of each vertex on some shortest path from `source` to that vertex. Returns `None` for any vertex
|
/// of each vertex on some shortest path from `source` to that vertex. Returns `None` for any vertex
|
||||||
/// not connected to `source`.
|
/// not connected to `source`.
|
||||||
///
|
///
|
||||||
|
/// Time complexity is *O((|V| + |E|) log |V|)*, space complexity is *O(|V|)*.
|
||||||
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Panics if `source` is not a valid vertex of `graph`.
|
/// Panics if `source` is not a valid vertex of `graph`.
|
||||||
@@ -95,6 +81,7 @@ pub struct DijkstraResult<V: Copy> {
|
|||||||
pub fn dijkstra<G, W>(graph: &G, source: G::Vertex, weights: W) -> DijkstraResult<G::Vertex>
|
pub fn dijkstra<G, W>(graph: &G, source: G::Vertex, weights: W) -> DijkstraResult<G::Vertex>
|
||||||
where
|
where
|
||||||
G: GraphTopology,
|
G: GraphTopology,
|
||||||
|
G::Vertex: Hash,
|
||||||
W: Fn(G::Edge) -> u32,
|
W: Fn(G::Edge) -> u32,
|
||||||
{
|
{
|
||||||
let mut predecessors = graph.vertex_map(None);
|
let mut predecessors = graph.vertex_map(None);
|
||||||
@@ -113,6 +100,8 @@ where
|
|||||||
/// by `weights` function. Returns the distances from `source` to each vertex. Returns `None` for any
|
/// by `weights` function. Returns the distances from `source` to each vertex. Returns `None` for any
|
||||||
/// vertex not connected to `source`.
|
/// vertex not connected to `source`.
|
||||||
///
|
///
|
||||||
|
/// Time complexity is *O((|V| + |E|) log |V|)*, space complexity is *O(|V|)*.
|
||||||
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Panics if `source` is not a valid vertex of `graph`.
|
/// Panics if `source` is not a valid vertex of `graph`.
|
||||||
@@ -142,6 +131,7 @@ pub fn dijkstra_distances<G, W>(
|
|||||||
) -> EntityMap<G::Vertex, Option<u32>>
|
) -> EntityMap<G::Vertex, Option<u32>>
|
||||||
where
|
where
|
||||||
G: GraphTopology,
|
G: GraphTopology,
|
||||||
|
G::Vertex: Hash,
|
||||||
W: Fn(G::Edge) -> u32,
|
W: Fn(G::Edge) -> u32,
|
||||||
{
|
{
|
||||||
dijkstra_impl(graph, source, weights, |_, _| {})
|
dijkstra_impl(graph, source, weights, |_, _| {})
|
||||||
@@ -153,6 +143,8 @@ where
|
|||||||
/// the distances from `source` to each vertex, and the predecessors of each vertex on some shortest
|
/// the distances from `source` to each vertex, and the predecessors of each vertex on some shortest
|
||||||
/// path from `source` to that vertex. Returns `None` for any vertex not connected to `source`.
|
/// path from `source` to that vertex. Returns `None` for any vertex not connected to `source`.
|
||||||
///
|
///
|
||||||
|
/// Time complexity is *O((|V| + |E|) log |V|)*, space complexity is *O(|V|)*.
|
||||||
|
///
|
||||||
/// Prefer [`bfs`] for unweighted graphs, it has better time and space complexity.
|
/// Prefer [`bfs`] for unweighted graphs, it has better time and space complexity.
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
@@ -179,6 +171,7 @@ where
|
|||||||
pub fn dijkstra_unweighted<G>(graph: &G, source: G::Vertex) -> DijkstraResult<G::Vertex>
|
pub fn dijkstra_unweighted<G>(graph: &G, source: G::Vertex) -> DijkstraResult<G::Vertex>
|
||||||
where
|
where
|
||||||
G: GraphTopology,
|
G: GraphTopology,
|
||||||
|
G::Vertex: Hash,
|
||||||
{
|
{
|
||||||
dijkstra(graph, source, |_| 1)
|
dijkstra(graph, source, |_| 1)
|
||||||
}
|
}
|
||||||
@@ -189,6 +182,8 @@ where
|
|||||||
/// the distances from `source` to each vertex. Returns `None` for any vertex not connected to
|
/// the distances from `source` to each vertex. Returns `None` for any vertex not connected to
|
||||||
/// `source`.
|
/// `source`.
|
||||||
///
|
///
|
||||||
|
/// Time complexity is *O((|V| + |E|) log |V|)*, space complexity is *O(|V|)*.
|
||||||
|
///
|
||||||
/// Prefer [`bfs_distances`] for unweighted graphs, it has better time and space complexity.
|
/// Prefer [`bfs_distances`] for unweighted graphs, it has better time and space complexity.
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
@@ -217,6 +212,7 @@ pub fn dijkstra_distances_unweighted<G>(
|
|||||||
) -> EntityMap<G::Vertex, Option<u32>>
|
) -> EntityMap<G::Vertex, Option<u32>>
|
||||||
where
|
where
|
||||||
G: GraphTopology,
|
G: GraphTopology,
|
||||||
|
G::Vertex: Hash,
|
||||||
{
|
{
|
||||||
dijkstra_distances(graph, source, |_| 1)
|
dijkstra_distances(graph, source, |_| 1)
|
||||||
}
|
}
|
||||||
@@ -229,32 +225,27 @@ fn dijkstra_impl<G, W, F>(
|
|||||||
) -> EntityMap<G::Vertex, Option<u32>>
|
) -> EntityMap<G::Vertex, Option<u32>>
|
||||||
where
|
where
|
||||||
G: GraphTopology,
|
G: GraphTopology,
|
||||||
|
G::Vertex: Hash,
|
||||||
W: Fn(G::Edge) -> u32,
|
W: Fn(G::Edge) -> u32,
|
||||||
F: FnMut(G::Vertex, G::Vertex),
|
F: FnMut(G::Vertex, G::Vertex),
|
||||||
{
|
{
|
||||||
let mut distances = graph.vertex_map(None);
|
let mut distances = graph.vertex_map(None);
|
||||||
let mut heap = BinaryHeap::new();
|
let mut heap = PriorityQueue::new();
|
||||||
|
|
||||||
distances[source] = Some(0);
|
distances[source] = Some(0);
|
||||||
heap.push(DistanceOrderedVertex {
|
heap.push(source, Reverse(0u32));
|
||||||
vertex: source,
|
|
||||||
distance: 0,
|
|
||||||
});
|
|
||||||
|
|
||||||
while let Some(v) = heap.pop() {
|
while let Some((v, Reverse(v_distance))) = heap.pop() {
|
||||||
for incidence in graph.incidences(v.vertex) {
|
for incidence in graph.incidences(v) {
|
||||||
let new_distance = distances[v.vertex].unwrap() + weights(incidence.1);
|
let new_distance = v_distance + weights(incidence.1);
|
||||||
if match distances[incidence.0] {
|
if match distances[incidence.0] {
|
||||||
None => true,
|
None => true,
|
||||||
Some(old_distance) if old_distance > new_distance => true,
|
Some(old_distance) if old_distance > new_distance => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
} {
|
} {
|
||||||
distances[incidence.0] = Some(new_distance);
|
distances[incidence.0] = Some(new_distance);
|
||||||
on_relax(incidence.0, v.vertex);
|
on_relax(incidence.0, v);
|
||||||
heap.push(DistanceOrderedVertex {
|
heap.push_increase(incidence.0, Reverse(new_distance));
|
||||||
vertex: incidence.0,
|
|
||||||
distance: new_distance,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,14 +7,14 @@ use crate::traits::{GraphTopology, IncidenceCursor};
|
|||||||
///
|
///
|
||||||
/// Handles are stable for the lifetime of the graph. Obtain via graph methods like
|
/// Handles are stable for the lifetime of the graph. Obtain via graph methods like
|
||||||
/// [`AppendGraph::add_vertex`] and [`AppendGraph::vertices`].
|
/// [`AppendGraph::add_vertex`] and [`AppendGraph::vertices`].
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
|
||||||
pub struct Vertex(usize);
|
pub struct Vertex(usize);
|
||||||
|
|
||||||
/// An opaque handle identifying an edge in an [`AppendGraph`].
|
/// An opaque handle identifying an edge in an [`AppendGraph`].
|
||||||
///
|
///
|
||||||
/// Handles are stable for the lifetime of the graph. Obtain via graph methods like
|
/// Handles are stable for the lifetime of the graph. Obtain via graph methods like
|
||||||
/// [`AppendGraph::add_edge`] and [`AppendGraph::edges`].
|
/// [`AppendGraph::add_edge`] and [`AppendGraph::edges`].
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
|
||||||
pub struct Edge(usize);
|
pub struct Edge(usize);
|
||||||
|
|
||||||
/// An [`EntityMap`] for [`AppendGraph`] vertices.
|
/// An [`EntityMap`] for [`AppendGraph`] vertices.
|
||||||
|
|||||||
Reference in New Issue
Block a user