Add algorithms::bfs_find_path
This commit is contained in:
+109
-3
@@ -425,10 +425,8 @@ where
|
||||
F: FnMut(G::Vertex, G::Vertex) -> bool,
|
||||
{
|
||||
let mut distances = graph.vertex_map(None);
|
||||
let mut queue = VecDeque::new();
|
||||
|
||||
distances[source] = Some(0);
|
||||
queue.push_back(source);
|
||||
let mut queue = VecDeque::from([source]);
|
||||
|
||||
while let Some(v) = queue.pop_front() {
|
||||
for neighbor in graph.adjacent_vertices(v) {
|
||||
@@ -451,6 +449,114 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// [Breadth-first search] from `source` for `target`, returns some shortest path as a sequence of
|
||||
/// edges.
|
||||
///
|
||||
/// Traverses vertices in `graph` starting from `source` until `target` is found, exploring all
|
||||
/// neighbors before descending further. Returns some shortest path from `source` to `target` as a
|
||||
/// sequence of edges in traversal order if `target` is a valid vertex of `graph` connected to
|
||||
/// `source`, or `None` otherwise. The returned path is empty if and only if `source` equals
|
||||
/// `target`.
|
||||
///
|
||||
/// Time complexity is *O(|V| + |E|)*, space complexity is *O(|V|)*.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `source` is not a valid vertex of `graph`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use grapherity::prelude::*;
|
||||
/// # use grapherity::algorithms::bfs_find_path;
|
||||
/// # use grapherity::models::Graph;
|
||||
/// let mut graph = Graph::new();
|
||||
/// let source = graph.add_vertex();
|
||||
/// let target = graph.add_vertex();
|
||||
/// let e = graph.add_edge(source, target);
|
||||
///
|
||||
/// assert_eq!(bfs_find_path(&graph, source, target), Some(vec![e]));
|
||||
/// ```
|
||||
///
|
||||
/// [Breadth-first search]: https://en.wikipedia.org/wiki/Breadth-first_search
|
||||
pub fn bfs_find_path<G>(graph: &G, source: G::Vertex, target: G::Vertex) -> Option<Vec<G::Edge>>
|
||||
where
|
||||
G: GraphTopology,
|
||||
{
|
||||
bfs_find_path_where(graph, source, |v| v == target)
|
||||
}
|
||||
|
||||
/// [Breadth-first search] from `source` for a vertex matching `predicate`, returns some shortest
|
||||
/// path as a sequence of edges.
|
||||
///
|
||||
/// Traverses vertices in `graph` starting from `source` until a vertex satisfying `predicate` is
|
||||
/// found, exploring all neighbors before descending further. Returns some shortest path from
|
||||
/// `source` to the first vertex satisfying `predicate` as a sequence of edges in traversal order,
|
||||
/// or `None` if no such vertex is connected to `source`. The returned path is empty if and only if
|
||||
/// `source` satisfies `predicate`.
|
||||
///
|
||||
/// Time complexity is *O(|V| + |E|)*, space complexity is *O(|V|)*.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `source` is not a valid vertex of `graph`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use grapherity::prelude::*;
|
||||
/// # use grapherity::algorithms::bfs_find_path_where;
|
||||
/// # use grapherity::models::Graph;
|
||||
/// let mut graph = Graph::new();
|
||||
/// let source = graph.add_vertex();
|
||||
/// let target = graph.add_vertex();
|
||||
/// let e = graph.add_edge(source, target);
|
||||
///
|
||||
/// assert_eq!(bfs_find_path_where(&graph, source, |v| v == target), Some(vec![e]));
|
||||
/// ```
|
||||
///
|
||||
/// [Breadth-first search]: https://en.wikipedia.org/wiki/Breadth-first_search
|
||||
pub fn bfs_find_path_where<G, P>(graph: &G, source: G::Vertex, predicate: P) -> Option<Vec<G::Edge>>
|
||||
where
|
||||
G: GraphTopology,
|
||||
P: Fn(G::Vertex) -> bool,
|
||||
{
|
||||
if predicate(source) {
|
||||
return Some(vec![]);
|
||||
}
|
||||
|
||||
let mut visited = graph.vertex_map(false);
|
||||
visited[source] = true;
|
||||
let mut predecessor: ElementMap<G::Vertex, Option<(G::Vertex, G::Edge)>> =
|
||||
graph.vertex_map(None);
|
||||
let mut queue = VecDeque::from([source]);
|
||||
|
||||
while let Some(v) = queue.pop_front() {
|
||||
for Incidence {
|
||||
vertex: neighbor,
|
||||
edge,
|
||||
} in graph.incidences(v)
|
||||
{
|
||||
if !visited[neighbor] {
|
||||
visited[neighbor] = true;
|
||||
predecessor[neighbor] = Some((v, edge));
|
||||
if predicate(neighbor) {
|
||||
let mut path = vec![edge];
|
||||
let mut current = v;
|
||||
while let Some((prev, e)) = predecessor[current] {
|
||||
path.push(e);
|
||||
current = prev;
|
||||
}
|
||||
path.reverse();
|
||||
return Some(path);
|
||||
}
|
||||
queue.push_back(neighbor);
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
// TODO: 'visited' is already encoded in 'predecessors', except for 'source', which is visited, but has no predecessor.
|
||||
/// Return data type for [`dfs`].
|
||||
pub struct DfsResult<V: Copy> {
|
||||
|
||||
Reference in New Issue
Block a user