22 std::vector<size_t> parent;
23 std::vector<size_t> rank;
26 explicit UnionFind(
size_t n) : parent(n), rank(n, 0) {
27 for (
size_t i = 0; i < n; ++i) {
32 size_t find(
size_t x) {
34 parent[x] = find(parent[x]);
39 bool unite(
size_t a,
size_t b) {
40 size_t rootA = find(a);
41 size_t rootB = find(b);
45 if (rank[rootA] < rank[rootB]) {
46 std::swap(rootA, rootB);
48 parent[rootB] = rootA;
49 if (rank[rootA] == rank[rootB]) {
55 bool connected(
size_t a,
size_t b) {
56 return find(a) == find(b);
70template<Graph G,
typename W>
71requires std::totally_ordered<std::invoke_result_t<W, const typename G::node_type&, const typename G::node_type&>>
74 W
const& weightFunction,
77 using N =
typename G::node_type;
78 using E =
typename G::edge_type;
79 using H =
typename G::adj_container_type::hash_function;
80 using Eq =
typename G::adj_container_type::equality_predicate;
82 auto nodes = graph.getNodes();
83 size_t nodeCount = std::ranges::distance(nodes);
86 return std::move(mst);
90 for (
const auto& node : nodes) {
93 return std::move(mst);
97 std::unordered_map<N, size_t, H, Eq> nodeToIndex;
98 nodeToIndex.reserve(nodeCount);
100 for (
const auto& node : nodes) {
101 nodeToIndex[node] = idx++;
105 auto weightComparator = [&weightFunction](
const E& lhs,
const E& rhs) {
106 return weightFunction(lhs.getFrom(), lhs.getTo()) < weightFunction(rhs.getFrom(), rhs.getTo());
108 std::ranges::sort(edges, weightComparator);
110 UnionFind uf(nodeCount);
111 size_t edgesAdded = 0;
112 size_t targetEdges = nodeCount - 1;
114 for (
const auto& edge : edges) {
115 size_t fromIdx = nodeToIndex.at(edge.getFrom());
116 size_t toIdx = nodeToIndex.at(edge.getTo());
117 if (not uf.connected(fromIdx, toIdx)) {
118 uf.unite(fromIdx, toIdx);
119 mst.addEdge(edge.getFrom(), edge.getTo());
121 if (edgesAdded == targetEdges) {
127 if (edgesAdded != targetEdges) {
130 return std::move(mst);
147template<Graph G,
typename W>
148requires std::totally_ordered<std::invoke_result_t<W, const typename G::node_type&, const typename G::node_type&>> && std::is_default_constructible_v<G>
151 W
const& weightFunction
153 return __impl::kruskalImpl<G, W>(graph, weightFunction, G());
169template<Graph G,
typename W>
170requires std::totally_ordered<std::invoke_result_t<W, const typename G::node_type&, const typename G::node_type&>>
173 W
const& weightFunction,
176 return __impl::kruskalImpl<G, W>(graph, weightFunction, std::forward<G>(outputGraph));
fishnet::Option< G > kruskal(const G &graph, W const &weightFunction)
Compute the Minimum Spanning Tree of a graph using Kruskal's algorithm.
Definition MSTAlgorithm.hpp:149