| //! Minimum Spanning Tree algorithms. |
| |
| use std::collections::{BinaryHeap, HashMap}; |
| |
| use crate::prelude::*; |
| |
| use crate::data::Element; |
| use crate::scored::MinScored; |
| use crate::unionfind::UnionFind; |
| use crate::visit::{Data, IntoNodeReferences, NodeRef}; |
| use crate::visit::{IntoEdgeReferences, NodeIndexable}; |
| |
| /// \[Generic\] Compute a *minimum spanning tree* of a graph. |
| /// |
| /// The input graph is treated as if undirected. |
| /// |
| /// Using Kruskal's algorithm with runtime **O(|E| log |E|)**. We actually |
| /// return a minimum spanning forest, i.e. a minimum spanning tree for each connected |
| /// component of the graph. |
| /// |
| /// The resulting graph has all the vertices of the input graph (with identical node indices), |
| /// and **|V| - c** edges, where **c** is the number of connected components in `g`. |
| /// |
| /// Use `from_elements` to create a graph from the resulting iterator. |
| pub fn min_spanning_tree<G>(g: G) -> MinSpanningTree<G> |
| where |
| G::NodeWeight: Clone, |
| G::EdgeWeight: Clone + PartialOrd, |
| G: IntoNodeReferences + IntoEdgeReferences + NodeIndexable, |
| { |
| // Initially each vertex is its own disjoint subgraph, track the connectedness |
| // of the pre-MST with a union & find datastructure. |
| let subgraphs = UnionFind::new(g.node_bound()); |
| |
| let edges = g.edge_references(); |
| let mut sort_edges = BinaryHeap::with_capacity(edges.size_hint().0); |
| for edge in edges { |
| sort_edges.push(MinScored( |
| edge.weight().clone(), |
| (edge.source(), edge.target()), |
| )); |
| } |
| |
| MinSpanningTree { |
| graph: g, |
| node_ids: Some(g.node_references()), |
| subgraphs, |
| sort_edges, |
| node_map: HashMap::new(), |
| node_count: 0, |
| } |
| } |
| |
| /// An iterator producing a minimum spanning forest of a graph. |
| #[derive(Debug, Clone)] |
| pub struct MinSpanningTree<G> |
| where |
| G: Data + IntoNodeReferences, |
| { |
| graph: G, |
| node_ids: Option<G::NodeReferences>, |
| subgraphs: UnionFind<usize>, |
| #[allow(clippy::type_complexity)] |
| sort_edges: BinaryHeap<MinScored<G::EdgeWeight, (G::NodeId, G::NodeId)>>, |
| node_map: HashMap<usize, usize>, |
| node_count: usize, |
| } |
| |
| impl<G> Iterator for MinSpanningTree<G> |
| where |
| G: IntoNodeReferences + NodeIndexable, |
| G::NodeWeight: Clone, |
| G::EdgeWeight: PartialOrd, |
| { |
| type Item = Element<G::NodeWeight, G::EdgeWeight>; |
| |
| fn next(&mut self) -> Option<Self::Item> { |
| let g = self.graph; |
| if let Some(ref mut iter) = self.node_ids { |
| if let Some(node) = iter.next() { |
| self.node_map.insert(g.to_index(node.id()), self.node_count); |
| self.node_count += 1; |
| return Some(Element::Node { |
| weight: node.weight().clone(), |
| }); |
| } |
| } |
| self.node_ids = None; |
| |
| // Kruskal's algorithm. |
| // Algorithm is this: |
| // |
| // 1. Create a pre-MST with all the vertices and no edges. |
| // 2. Repeat: |
| // |
| // a. Remove the shortest edge from the original graph. |
| // b. If the edge connects two disjoint trees in the pre-MST, |
| // add the edge. |
| while let Some(MinScored(score, (a, b))) = self.sort_edges.pop() { |
| // check if the edge would connect two disjoint parts |
| let (a_index, b_index) = (g.to_index(a), g.to_index(b)); |
| if self.subgraphs.union(a_index, b_index) { |
| let (&a_order, &b_order) = |
| match (self.node_map.get(&a_index), self.node_map.get(&b_index)) { |
| (Some(a_id), Some(b_id)) => (a_id, b_id), |
| _ => panic!("Edge references unknown node"), |
| }; |
| return Some(Element::Edge { |
| source: a_order, |
| target: b_order, |
| weight: score, |
| }); |
| } |
| } |
| None |
| } |
| } |