//! 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) -> MinSpanningTree 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 where G: Data + IntoNodeReferences, { graph: G, node_ids: Option, subgraphs: UnionFind, #[allow(clippy::type_complexity)] sort_edges: BinaryHeap>, node_map: HashMap, node_count: usize, } impl Iterator for MinSpanningTree where G: IntoNodeReferences + NodeIndexable, G::NodeWeight: Clone, G::EdgeWeight: PartialOrd, { type Item = Element; fn next(&mut self) -> Option { 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 } }