|
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/traversal/depth_first_search.hpp |
| 6 | +/// @brief Concrete Depth-First Search (DFS) algorithm implementations (iterative and recursive). |
| 7 | + |
5 | 8 | #pragma once |
6 | 9 |
|
7 | 10 | #include "gl/algorithm/core.hpp" |
|
11 | 14 |
|
12 | 15 | namespace gl::algorithm { |
13 | 16 |
|
| 17 | +/// @ingroup GL GL-Algorithm |
| 18 | +/// @brief Executes a concrete iterative Depth-First Search (DFS) traversal over the graph. |
| 19 | +/// |
| 20 | +/// This function utilizes the generic @ref gl::algorithm::dfs "dfs" engine to perform a standard, stack-based traversal. |
| 21 | +/// It automatically manages the visited states and predecessor tracking. |
| 22 | +/// |
| 23 | +/// If a specific `root_vertex_id` is provided, the algorithm explores only the connected component |
| 24 | +/// reachable from that root. If `no_root` is used, it iteratively ensures that every disconnected |
| 25 | +/// component in the entire graph is fully traversed. |
| 26 | +/// |
| 27 | +/// ### Example Usage |
| 28 | +/// ```cpp |
| 29 | +/// // Standard execution returning a predecessor map for the whole graph |
| 30 | +/// auto pred_map = gl::algorithm::depth_first_search(graph); // (1)! |
| 31 | +/// ``` |
| 32 | +/// |
| 33 | +/// 1\. Explores every vertex in the graph and builds a complete predecessor forest. |
| 34 | +/// |
| 35 | +/// ### Example Usage |
| 36 | +/// ```cpp |
| 37 | +/// auto pred_map = gl::algorithm::depth_first_search(graph, start_id); // (1)! |
| 38 | +/// |
| 39 | +/// gl::algorithm::depth_first_search<gl::algorithm::noret>( // (2)! |
| 40 | +/// graph, |
| 41 | +/// gl::algorithm::no_root, // (3)! |
| 42 | +/// [](auto v) { std::cout << "Discovered: " << v << '\n'; } // (4)! |
| 43 | +/// ); |
| 44 | +/// ``` |
| 45 | +/// |
| 46 | +/// 1\. Standard execution returning a predecessor map from a specific root. Traverses only the component reachable from `start_id` and builds a predecessor tree. |
| 47 | +/// |
| 48 | +/// 2\. Execution purely for side-effects over the entire graph. Uses the @ref gl::algorithm::result_discriminator "noret" discriminator to completely compile away the predecessor map allocations. |
| 49 | +/// |
| 50 | +/// 3\. Traverses all vertices in the graph, regardless of disconnected components. |
| 51 | +/// |
| 52 | +/// 4\. A custom `PreVisitCallback` executed when a vertex is popped from the stack. |
| 53 | +/// |
| 54 | +/// > [!INFO] Algorithmic Complexity |
| 55 | +/// > |
| 56 | +/// > The time complexity depends entirely on the underlying representation of `GraphType`: |
| 57 | +/// > - **Adjacency List Representations**: \f$O(|V| + |E|)\f$ |
| 58 | +/// > - *Includes:* @ref gl::impl::list_t "list_t" and @ref gl::impl::flat_list_t "flat_list_t". |
| 59 | +/// > - **Adjacency Matrix Representations**: \f$O(|V|^2)\f$ |
| 60 | +/// > - *Includes:* @ref gl::impl::matrix_t "matrix_t" and @ref gl::impl::flat_matrix_t "flat_matrix_t". |
| 61 | +/// > - *Note:* Iterating over adjacent vertices requires scanning the entire \f$|V|\f$-length matrix row. |
| 62 | +/// |
| 63 | +/// ### Template Parameters |
| 64 | +/// | Parameter | Description | |
| 65 | +/// | :-------- | :--- | |
| 66 | +/// | `Result` | Discriminator dictating if the algorithm should return a predecessor map (`ret`) or `void` (`noret`). | |
| 67 | +/// | `G` | The type of the graph being traversed. | |
| 68 | +/// | `PreVisitCallback` | Type of the callable executed immediately before a vertex is officially visited. | |
| 69 | +/// | `PostVisitCallback` | Type of the callable executed after all adjacent edges of a vertex are evaluated. | |
| 70 | +/// |
| 71 | +/// @param graph The graph to traverse. |
| 72 | +/// @param root_vertex_id The starting vertex for the search. Defaults to @ref gl::algorithm::no_root "no_root" to traverse the entire graph. |
| 73 | +/// @param pre_visit Hook executed immediately before the internal visit logic. |
| 74 | +/// @param post_visit Hook executed after all adjacent edges of the current vertex have been evaluated. |
| 75 | +/// @return A @ref gl::algorithm::predecessors_map "predecessors_map" mapping each visited vertex to its parent if `Result == ret`. Returns `void` otherwise. |
14 | 76 | template < |
15 | 77 | result_discriminator Result = ret, |
16 | 78 | traits::c_graph G, |
@@ -59,6 +121,58 @@ result_type<Result, predecessors_map<G>> depth_first_search( |
59 | 121 | return pred_map; |
60 | 122 | } |
61 | 123 |
|
| 124 | +/// @ingroup GL GL-Algorithm |
| 125 | +/// @brief Executes a concrete recursive Depth-First Search (DFS) traversal over the graph. |
| 126 | +/// |
| 127 | +/// This function relies on the generic @ref gl::algorithm::r_dfs "r_dfs" engine. Instead of a |
| 128 | +/// heap-allocated stack, it utilizes the C++ call stack to navigate the graph. |
| 129 | +/// |
| 130 | +/// > [!WARNING] Call Stack Depth |
| 131 | +/// > |
| 132 | +/// > While recursive DFS can be slightly faster due to the lack of heap allocations, it is |
| 133 | +/// > vulnerable to Stack Overflow errors on extremely deep graphs (e.g., long linear paths). |
| 134 | +/// |
| 135 | +/// ### Example Usage |
| 136 | +/// ```cpp |
| 137 | +/// // Execution purely for side-effects from a specific root |
| 138 | +/// gl::algorithm::recursive_depth_first_search<gl::algorithm::noret>( // (1)! |
| 139 | +/// graph, |
| 140 | +/// start_id, // (2)! |
| 141 | +/// [](auto v) { std::cout << "Entering subtree of: " << v << '\n'; }, // (3)! |
| 142 | +/// [](auto v) { std::cout << "Exiting subtree of: " << v << '\n'; } // (4)! |
| 143 | +/// ); |
| 144 | +/// ``` |
| 145 | +/// |
| 146 | +/// 1\. Execution purely for side-effects over the entire graph. Uses the @ref gl::algorithm::result_discriminator "noret" discriminator to completely compile away the predecessor map allocations. |
| 147 | +/// |
| 148 | +/// 2\. Initiates the recursion from `start_id`. |
| 149 | +/// |
| 150 | +/// 3\. Hook triggered before descending into the current vertex's adjacent neighbors. |
| 151 | +/// |
| 152 | +/// 4\. Hook triggered after returning from all recursive calls for the current vertex. |
| 153 | +/// |
| 154 | +/// > [!INFO] Algorithmic Complexity |
| 155 | +/// > |
| 156 | +/// > The time complexity depends entirely on the underlying representation of `GraphType`: |
| 157 | +/// > - **Adjacency List Representations**: \f$O(|V| + |E|)\f$ |
| 158 | +/// > - *Includes:* @ref gl::impl::list_t "list_t" and @ref gl::impl::flat_list_t "flat_list_t". |
| 159 | +/// > - **Adjacency Matrix Representations**: \f$O(|V|^2)\f$ |
| 160 | +/// > - *Includes:* @ref gl::impl::matrix_t "matrix_t" and @ref gl::impl::flat_matrix_t "flat_matrix_t". |
| 161 | +/// > - *Note:* Iterating over adjacent vertices requires scanning the entire \f$|V|\f$-length matrix row. |
| 162 | +/// |
| 163 | +/// ### Template Parameters |
| 164 | +/// | Parameter | Description | |
| 165 | +/// | :-------- | :--- | |
| 166 | +/// | `Result` | Discriminator dictating if the algorithm should return a predecessor map (`ret`) or `void` (`noret`). | |
| 167 | +/// | `G` | The type of the graph being traversed. | |
| 168 | +/// | `PreVisitCallback` | Type of the callable executed immediately before a vertex is officially visited. | |
| 169 | +/// | `PostVisitCallback` | Type of the callable executed after all adjacent edges of a vertex are evaluated. | |
| 170 | +/// |
| 171 | +/// @param graph The graph to traverse. |
| 172 | +/// @param root_vertex_id The starting vertex for the search. Defaults to @ref gl::algorithm::no_root "no_root" to traverse the entire graph. |
| 173 | +/// @param pre_visit Hook executed immediately before the internal visit logic. |
| 174 | +/// @param post_visit Hook executed after returning from all recursive calls for the current vertex. |
| 175 | +/// @return A @ref gl::algorithm::predecessors_map "predecessors_map" mapping each visited vertex to its parent if `Result == ret`. Returns `void` otherwise. |
62 | 176 | template < |
63 | 177 | result_discriminator Result = ret, |
64 | 178 | traits::c_graph G, |
|
0 commit comments