|
2 | 2 | // This file is part of the CPP-GL project (https://github.com/SpectraL519/cpp-gl). |
3 | 3 | // Licensed under the MIT License. See the LICENSE file in the project root for full license information. |
4 | 4 |
|
| 5 | +/// @file gl/algorithm/spanning_tree/prim_mst.hpp |
| 6 | +/// @brief Concrete implementations of Prim's Minimum Spanning Tree (MST) algorithm. |
| 7 | + |
5 | 8 | #pragma once |
6 | 9 |
|
7 | 10 | #include "gl/algorithm/util.hpp" |
|
12 | 15 |
|
13 | 16 | namespace gl::algorithm { |
14 | 17 |
|
| 18 | +/// @ingroup GL GL-Algorithm |
| 19 | +/// @brief A descriptor structure holding the results of a Minimum Spanning Tree (MST) execution. |
| 20 | +/// |
| 21 | +/// @tparam G The type of the undirected graph. Must satisfy the [**c_undirected_graph**](gl_concepts.md#gl-traits-c-undirected-graph) concept. |
15 | 22 | template <traits::c_undirected_graph G> |
16 | 23 | struct mst_descriptor { |
| 24 | + /// @brief The type of the graph. |
17 | 25 | using graph_type = G; |
| 26 | + /// @brief The type of the edges stored in the graph. |
18 | 27 | using edge_type = typename graph_type::edge_type; |
| 28 | + /// @brief The numeric type used to represent accumulated tree weights. |
19 | 29 | using weight_type = vertex_distance_type<graph_type>; |
20 | 30 |
|
| 31 | + /// @brief Constructs a descriptor sized to hold the resulting tree edges. |
| 32 | + /// @param n_vertices The total number of vertices in the graph. |
21 | 33 | mst_descriptor(const size_type n_vertices) { |
22 | 34 | edges.reserve(n_vertices - 1uz); |
23 | 35 | } |
24 | 36 |
|
| 37 | + /// @brief The sequence of edges that form the Minimum Spanning Tree. |
25 | 38 | std::vector<edge_type> edges; |
| 39 | + /// @brief The accumulated minimum weight/cost of the entire spanning tree. |
26 | 40 | weight_type weight = static_cast<weight_type>(0); |
27 | 41 | }; |
28 | 42 |
|
| 43 | +/// @ingroup GL GL-Algorithm |
| 44 | +/// @brief Computes the Minimum Spanning Tree (MST) of an undirected graph using Prim's algorithm with an edge-based priority queue. |
| 45 | +/// |
| 46 | +/// This implementation uses a standard binary heap (`std::priority_queue`) to store and sort edges based on their weight. |
| 47 | +/// It pushes newly discovered adjacent edges into the queue and safely ignores those that lead to already-visited vertices. |
| 48 | +/// |
| 49 | +/// ### Example Usage |
| 50 | +/// ```cpp |
| 51 | +/// auto mst = gl::algorithm::edge_heap_prim_mst(graph, start_id); // (1)! |
| 52 | +/// std::cout << "Total MST Weight: " << mst.weight |
| 53 | +/// << "\nMST Edges: " << gl::io::set_formatter(mst.edges) << '\n'; |
| 54 | +/// ``` |
| 55 | +/// |
| 56 | +/// 1\. Computes the MST starting from the given `start_id`. If `invalid_id` is passed, it defaults to the graph's `initial_id`. |
| 57 | +/// |
| 58 | +/// > [!INFO] Algorithmic Complexity |
| 59 | +/// > |
| 60 | +/// > The time complexity depends on the underlying representation of `GraphType` and the queue overhead: |
| 61 | +/// > - **Adjacency List Representations**: \f$O(|E| \log |E|)\f$ |
| 62 | +/// > - *Includes:* @ref gl::impl::list_t "list_t" and @ref gl::impl::flat_list_t "flat_list_t". |
| 63 | +/// > - *Note:* In simple graphs, this simplifies to \f$O(|E| \log |V|)\f$. However, because list models allow multigraphs, the queue size and operations scale strictly with \f$|E|\f$. |
| 64 | +/// > - **Adjacency Matrix Representations**: \f$O(|V|^2 + |E| \log |V|)\f$ |
| 65 | +/// > - *Includes:* @ref gl::impl::matrix_t "matrix_t" and @ref gl::impl::flat_matrix_t "flat_matrix_t". |
| 66 | +/// > - *Note:* Iterating over incident edges requires scanning the entire \f$|V|\f$-length matrix row. Since matrices represent simple graphs, the heap operations safely simplify to \f$O(\log |V|)\f$. |
| 67 | +/// |
| 68 | +/// ### Template Parameters |
| 69 | +/// | Parameter | Description | Constraint | |
| 70 | +/// | :-------- | :--- | :--- | |
| 71 | +/// | G | The type of the undirected graph being traversed. | Must satisfy the [**c_undirected_graph**](gl_concepts.md#gl-traits-c-undirected-graph) concept. | |
| 72 | +/// |
| 73 | +/// @param graph The undirected graph to evaluate. |
| 74 | +/// @param root_id The starting vertex ID for the MST calculation. Defaults to the graph's `initial_id` if `invalid_id` is passed. |
| 75 | +/// @return A @ref gl::algorithm::mst_descriptor "mst_descriptor" containing the accumulated minimum weight and the sequence of edges forming the tree. |
| 76 | +/// @see @ref gl::algorithm::vertex_heap_prim_mst "vertex_heap_prim_mst" For the vertex-heap variant of the Prim's MST finding algorithm. |
| 77 | +/// @hideparams |
29 | 78 | template <traits::c_undirected_graph G> |
30 | 79 | [[nodiscard]] mst_descriptor<G> edge_heap_prim_mst(const G& graph, typename G::id_type root_id) { |
31 | 80 | // type definitions |
@@ -83,8 +132,42 @@ template <traits::c_undirected_graph G> |
83 | 132 | return mst; |
84 | 133 | } |
85 | 134 |
|
| 135 | +/// @ingroup GL GL-Algorithm |
| 136 | +/// @brief Computes the Minimum Spanning Tree (MST) of an undirected graph using Prim's algorithm with a vertex-based array heap. |
| 137 | +/// |
| 138 | +/// This variation maintains a heap of vertex IDs based on their minimum known connection cost. |
| 139 | +/// Because standard C++ heaps do not support a `decrease_key` operation, this implementation |
| 140 | +/// dynamically rebuilds the heap (`std::make_heap`) at the end of each iteration to reflect updated distances. |
| 141 | +/// |
| 142 | +/// ### Example Usage |
| 143 | +/// ```cpp |
| 144 | +/// auto mst = gl::algorithm::vertex_heap_prim_mst(graph, start_id); // (1)! |
| 145 | +/// std::cout << "Total MST Weight: " << mst.weight |
| 146 | +/// << "\nMST Edges: " << gl::io::set_formatter(mst.edges) << '\n'; |
| 147 | +/// ``` |
| 148 | +/// |
| 149 | +/// 1\. Computes the MST starting from the given `start_id`. Highly optimal for dense matrix graphs. |
| 150 | +/// |
| 151 | +/// > [!INFO] Algorithmic Complexity |
| 152 | +/// > |
| 153 | +/// > Due to rebuilding the heap (\f$O(|V|)\f$) up to \f$|V|\f$ times, combined with evaluating every edge, the strict time complexity is \f$O(|V|^2 + |E|)\f$: |
| 154 | +/// > - **Adjacency Matrix Representations**: \f$O(|V|^2)\f$ |
| 155 | +/// > - *Note:* Since matrix models inherently represent simple graphs (where \f$|E| \le |V|^2\f$), the complexity strictly simplifies to \f$O(|V|^2)\f$. This makes the vertex heap approach highly suitable for dense graphs. |
| 156 | +/// > - **Adjacency List Representations**: \f$O(|V|^2 + |E|)\f$ |
| 157 | +/// > - *Note:* For multigraphs, the edge count \f$|E|\f$ can exceed \f$|V|^2\f$, meaning the edge traversal phase will dictate the overall performance. |
| 158 | +/// |
| 159 | +/// ### Template Parameters |
| 160 | +/// | Parameter | Description | Constraint | |
| 161 | +/// | :-------- | :--- | :--- | |
| 162 | +/// | G | The type of the undirected graph being traversed. | Must satisfy the [**c_undirected_graph**](gl_concepts.md#gl-traits-c-undirected-graph) concept and its @ref gl::vertex_distance_type "distance type" must satisfy [**c_has_numeric_limits_max**](gl_concepts.md#gl-traits-c-has-numeric-limits-max). |
| 163 | +/// |
| 164 | +/// @param graph The undirected graph to evaluate. |
| 165 | +/// @param root_id The starting vertex ID for the MST calculation. Defaults to the graph's `initial_id` if `invalid_id` is passed. |
| 166 | +/// @return A @ref gl::algorithm::mst_descriptor "mst_descriptor" containing the accumulated minimum weight and the sequence of edges forming the tree. |
| 167 | +/// @see @ref gl::algorithm::edge_heap_prim_mst "edge_heap_prim_mst" For the vertex-heap variant of the Prim's MST finding algorithm. |
| 168 | +/// @hideparams |
86 | 169 | template <traits::c_undirected_graph G> |
87 | | -requires traits::c_has_numeric_limits_max<vertex_distance_type<G>> |
| 170 | +requires(traits::c_has_numeric_limits_max<vertex_distance_type<G>>) |
88 | 171 | [[nodiscard]] mst_descriptor<G> vertex_heap_prim_mst(const G& graph, typename G::id_type root_id) { |
89 | 172 | // type definitions |
90 | 173 | using id_type = typename G::id_type; |
|
0 commit comments