graph algorithms
parent
c33722ffba
commit
709159e6e3
@ -0,0 +1,133 @@
|
||||
use std::cmp::min;
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
|
||||
use itertools::Itertools;
|
||||
|
||||
struct TarjanScc<'a> {
|
||||
graph: &'a [Vec<usize>],
|
||||
id: usize,
|
||||
ids: Vec<Option<usize>>,
|
||||
low: Vec<usize>,
|
||||
on_stack: Vec<bool>,
|
||||
stack: Vec<usize>,
|
||||
}
|
||||
|
||||
impl<'a> TarjanScc<'a> {
|
||||
pub(crate) fn new(graph: &'a [Vec<usize>]) -> Self {
|
||||
Self {
|
||||
graph,
|
||||
id: 0,
|
||||
ids: vec![None; graph.len()],
|
||||
low: vec![0; graph.len()],
|
||||
on_stack: vec![false; graph.len()],
|
||||
stack: vec![],
|
||||
}
|
||||
}
|
||||
pub(crate) fn run(mut self) -> Vec<Vec<usize>> {
|
||||
for i in 0..self.graph.len() {
|
||||
if self.ids[i].is_none() {
|
||||
self.dfs(i)
|
||||
}
|
||||
}
|
||||
self.low
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.group_by(|(_id, scc)| *scc)
|
||||
.into_iter()
|
||||
.map(|(_scc, args)| args.map(|(id, _scc)| id).collect_vec())
|
||||
.collect_vec()
|
||||
}
|
||||
fn dfs(&mut self, at: usize) {
|
||||
self.stack.push(at);
|
||||
self.on_stack[at] = true;
|
||||
self.id += 1;
|
||||
self.ids[at] = Some(self.id);
|
||||
self.low[at] = self.id;
|
||||
for to in &self.graph[at] {
|
||||
let to = *to;
|
||||
if self.ids[to].is_none() {
|
||||
self.dfs(to);
|
||||
}
|
||||
if self.on_stack[to] {
|
||||
self.low[at] = min(self.low[at], self.low[to]);
|
||||
}
|
||||
}
|
||||
if self.ids[at].unwrap() == self.low[at] {
|
||||
while let Some(node) = self.stack.pop() {
|
||||
self.on_stack[node] = false;
|
||||
self.low[node] = self.ids[at].unwrap();
|
||||
if node == at {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type Graph<T> = BTreeMap<T, Vec<T>>;
|
||||
|
||||
pub(crate) fn strongly_connected_components<T>(graph: &Graph<T>) -> Vec<Vec<&T>>
|
||||
where
|
||||
T: Ord,
|
||||
{
|
||||
let indices = graph.keys().collect_vec();
|
||||
let invert_indices: BTreeMap<_, _> = indices
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(idx, k)| (*k, idx))
|
||||
.collect();
|
||||
let idx_graph = graph
|
||||
.values()
|
||||
.map(|vs| vs.iter().map(|v| invert_indices[v]).collect_vec())
|
||||
.collect_vec();
|
||||
TarjanScc::new(&idx_graph)
|
||||
.run()
|
||||
.into_iter()
|
||||
.map(|vs| vs.into_iter().map(|i| indices[i]).collect_vec())
|
||||
.collect_vec()
|
||||
}
|
||||
|
||||
struct Reachable<'a, T> {
|
||||
graph: &'a Graph<T>
|
||||
}
|
||||
|
||||
impl<'a, T: Ord> Reachable<'a, T> {
|
||||
fn walk(&self, starting: &T, collected: &mut BTreeSet<&'a T>) {
|
||||
for el in self.graph.get(starting).unwrap() {
|
||||
if collected.insert(el) {
|
||||
self.walk(el, collected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn reachable_components<'a, T: Ord>(graph: &'a Graph<T>, start: &'a T) -> BTreeSet<&'a T> {
|
||||
let mut collected = BTreeSet::from([start]);
|
||||
let worker = Reachable {graph};
|
||||
worker.walk(start, &mut collected);
|
||||
collected
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use crate::query::graph::{reachable_components, strongly_connected_components};
|
||||
|
||||
#[test]
|
||||
fn test_scc() {
|
||||
let graph = BTreeMap::from([
|
||||
("a", vec!["b"]),
|
||||
("b", vec!["a", "c"]),
|
||||
("c", vec!["a", "d", "e"]),
|
||||
("d", vec!["e", "e", "e"]),
|
||||
("e", vec![]),
|
||||
("f", vec![])
|
||||
]);
|
||||
let scc = strongly_connected_components(&graph);
|
||||
dbg!(scc);
|
||||
let reachable = reachable_components(&graph, &"a");
|
||||
dbg!(reachable);
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue