From d9267d03efe357821fa9e2ae742fe3526cac7944 Mon Sep 17 00:00:00 2001 From: Phil Ratzloff Date: Wed, 15 Apr 2026 22:46:26 -0400 Subject: [PATCH] D3128: add allocator parameters to algorithm synopses and documentation Add Alloc template parameter (defaulting to std::allocator) and const Alloc& alloc parameter to all algorithms that use internal dynamic storage: Traversal: - breadth_first_search (single- and multi-source) - depth_first_search - topological_sort (single-source, multi-source, full-graph) Shortest paths: - dijkstra_shortest_paths (single- and multi-source) - dijkstra_shortest_distances (single- and multi-source) Components: - articulation_points - biconnected_components - connected_components - kosaraju (both overloads) - tarjan_scc MST: - kruskal (both overloads) - inplace_kruskal (both overloads) - prim Update algorithms.tex: add alloc remarks to each affected algorithm section and fix lstinputlisting line ranges for connected_components.hpp and mst.hpp after synopsis expansion. --- D3128_Algorithms/src/breadth_first_search.hpp | 10 ++-- .../src/breadth_first_search_multi.hpp | 6 ++- D3128_Algorithms/src/connected_components.hpp | 22 ++++---- D3128_Algorithms/src/depth_first_search.hpp | 10 ++-- .../src/dijkstra_shortest_dists.hpp | 6 ++- .../src/dijkstra_shortest_dists_multi.hpp | 6 ++- .../src/dijkstra_shortest_paths.hpp | 6 ++- .../src/dijkstra_shortest_paths_multi.hpp | 18 ++++--- D3128_Algorithms/src/mst.hpp | 26 +++++---- D3128_Algorithms/src/tarjan_scc.hpp | 4 +- D3128_Algorithms/src/topological_sort.hpp | 10 ++-- .../src/topological_sort_multi.hpp | 6 ++- D3128_Algorithms/tex/algorithms.tex | 54 ++++++++++++++++--- 13 files changed, 126 insertions(+), 58 deletions(-) diff --git a/D3128_Algorithms/src/breadth_first_search.hpp b/D3128_Algorithms/src/breadth_first_search.hpp index 21d8ffa..2320885 100644 --- a/D3128_Algorithms/src/breadth_first_search.hpp +++ b/D3128_Algorithms/src/breadth_first_search.hpp @@ -1,5 +1,7 @@ -template +template > void breadth_first_search( - G&& g, // graph - vertex_id_t source, // starting vertex\_id - Visitor&& visitor = empty_visitor()) + G&& g, // graph + vertex_id_t source, // starting vertex\_id + Visitor&& visitor = empty_visitor(), + const Alloc& alloc = Alloc()) diff --git a/D3128_Algorithms/src/breadth_first_search_multi.hpp b/D3128_Algorithms/src/breadth_first_search_multi.hpp index ab43b62..4c7c23d 100644 --- a/D3128_Algorithms/src/breadth_first_search_multi.hpp +++ b/D3128_Algorithms/src/breadth_first_search_multi.hpp @@ -1,5 +1,7 @@ -template +template > requires convertible_to, vertex_id_t> void breadth_first_search(G&& g, // graph const Sources& sources, - Visitor&& visitor = empty_visitor()) + Visitor&& visitor = empty_visitor(), + const Alloc& alloc = Alloc()) diff --git a/D3128_Algorithms/src/connected_components.hpp b/D3128_Algorithms/src/connected_components.hpp index c2594ab..e2c32e6 100644 --- a/D3128_Algorithms/src/connected_components.hpp +++ b/D3128_Algorithms/src/connected_components.hpp @@ -1,22 +1,22 @@ /* * Hopcroft-Tarjan Articulation Points */ -template +template > requires output_iterator> -void articulation_points(G&& g, Iter cut_vertices); +void articulation_points(G&& g, Iter cut_vertices, const Alloc& alloc = Alloc()); /* * Hopcroft-Tarjan Biconnected Components */ -template -void biconnected_components(G&& g, OuterContainer& components); +template > +void biconnected_components(G&& g, OuterContainer& components, const Alloc& alloc = Alloc()); /* * Connected Components */ -template +template > requires vertex_property_fn_for -size_t connected_components(G&& g, ComponentFn&& component); +size_t connected_components(G&& g, ComponentFn&& component, const Alloc& alloc = Alloc()); /* * Afforest Connected Components @@ -32,10 +32,12 @@ void afforest(G&& g, GT&& g_t, Component& component, const size_t neighbor_round /* * Kosaraju Strongly Connected Components */ -template +template > requires vertex_property_fn_for -void kosaraju(G&& g, GT&& g_t, ComponentFn&& component); +void kosaraju(G&& g, GT&& g_t, ComponentFn&& component, const Alloc& alloc = Alloc()); -template +template > requires vertex_property_fn_for -void kosaraju(G&& g, ComponentFn&& component); +void kosaraju(G&& g, ComponentFn&& component, const Alloc& alloc = Alloc()); diff --git a/D3128_Algorithms/src/depth_first_search.hpp b/D3128_Algorithms/src/depth_first_search.hpp index 052f2d1..fec678e 100644 --- a/D3128_Algorithms/src/depth_first_search.hpp +++ b/D3128_Algorithms/src/depth_first_search.hpp @@ -1,5 +1,7 @@ -template +template > void depth_first_search( - G&& g, // graph - vertex_id_t source, // starting vertex\_id - Visitor&& visitor = empty_visitor()) + G&& g, // graph + vertex_id_t source, // starting vertex\_id + Visitor&& visitor = empty_visitor(), + const Alloc& alloc = Alloc()) diff --git a/D3128_Algorithms/src/dijkstra_shortest_dists.hpp b/D3128_Algorithms/src/dijkstra_shortest_dists.hpp index 9bd37b8..9bbc162 100644 --- a/D3128_Algorithms/src/dijkstra_shortest_dists.hpp +++ b/D3128_Algorithms/src/dijkstra_shortest_dists.hpp @@ -4,7 +4,8 @@ template &)>, class Visitor = empty_visitor, class Compare = less>, - class Combine = plus>> + class Combine = plus>, + class Alloc = allocator> requires distance_fn_for && basic_edge_weight_function, Compare, Combine> constexpr void dijkstra_shortest_distances( @@ -15,4 +16,5 @@ constexpr void dijkstra_shortest_distances( const edge_t& uv) { return distance_fn_value_t(1); }, Visitor&& visitor = empty_visitor(), Compare&& compare = less>(), - Combine&& combine = plus>()); + Combine&& combine = plus>(), + const Alloc& alloc = Alloc()); diff --git a/D3128_Algorithms/src/dijkstra_shortest_dists_multi.hpp b/D3128_Algorithms/src/dijkstra_shortest_dists_multi.hpp index 4213e69..8868b16 100644 --- a/D3128_Algorithms/src/dijkstra_shortest_dists_multi.hpp +++ b/D3128_Algorithms/src/dijkstra_shortest_dists_multi.hpp @@ -5,7 +5,8 @@ template &)>, class Visitor = empty_visitor, class Compare = less>, - class Combine = plus>> + class Combine = plus>, + class Alloc = allocator> requires distance_fn_for && convertible_to, vertex_id_t> && basic_edge_weight_function, Compare, Combine> @@ -17,4 +18,5 @@ constexpr void dijkstra_shortest_distances( const edge_t& uv) { return distance_fn_value_t(1); }, Visitor&& visitor = empty_visitor(), Compare&& compare = less>(), - Combine&& combine = plus>()); + Combine&& combine = plus>(), + const Alloc& alloc = Alloc()); diff --git a/D3128_Algorithms/src/dijkstra_shortest_paths.hpp b/D3128_Algorithms/src/dijkstra_shortest_paths.hpp index 79dc4bd..46c551f 100644 --- a/D3128_Algorithms/src/dijkstra_shortest_paths.hpp +++ b/D3128_Algorithms/src/dijkstra_shortest_paths.hpp @@ -5,7 +5,8 @@ template &)>, class Visitor = empty_visitor, class Compare = less>, - class Combine = plus>> + class Combine = plus>, + class Alloc = allocator> requires distance_fn_for && predecessor_fn_for && basic_edge_weight_function, Compare, Combine> @@ -18,4 +19,5 @@ constexpr void dijkstra_shortest_paths( const edge_t& uv) { return distance_fn_value_t(1); }, Visitor&& visitor = empty_visitor(), Compare&& compare = less>(), - Combine&& combine = plus>()); + Combine&& combine = plus>(), + const Alloc& alloc = Alloc()); diff --git a/D3128_Algorithms/src/dijkstra_shortest_paths_multi.hpp b/D3128_Algorithms/src/dijkstra_shortest_paths_multi.hpp index 9e891e0..e309b4c 100644 --- a/D3128_Algorithms/src/dijkstra_shortest_paths_multi.hpp +++ b/D3128_Algorithms/src/dijkstra_shortest_paths_multi.hpp @@ -6,18 +6,20 @@ template &)>, class Visitor = empty_visitor, class Compare = less>, - class Combine = plus>> + class Combine = plus>, + class Alloc = allocator> requires distance_fn_for && predecessor_fn_for && convertible_to, vertex_id_t> && basic_edge_weight_function, Compare, Combine> constexpr void dijkstra_shortest_paths( - G&& g, - const Sources& sources, - DistanceFn&& distance, + G&& g, + const Sources& sources, + DistanceFn&& distance, PredecessorFn&& predecessor, - WF&& weight = [](const auto&, + WF&& weight = [](const auto&, const edge_t& uv) { return distance_fn_value_t(1); }, - Visitor&& visitor = empty_visitor(), - Compare&& compare = less>(), - Combine&& combine = plus>()); + Visitor&& visitor = empty_visitor(), + Compare&& compare = less>(), + Combine&& combine = plus>(), + const Alloc& alloc = Alloc()); diff --git a/D3128_Algorithms/src/mst.hpp b/D3128_Algorithms/src/mst.hpp index bdef65a..7c82e21 100644 --- a/D3128_Algorithms/src/mst.hpp +++ b/D3128_Algorithms/src/mst.hpp @@ -1,22 +1,26 @@ /* * Kruskal's Algorithm */ -template -auto kruskal(IELR&& e, OELR&& t); +template > +auto kruskal(IELR&& e, OELR&& t, const Alloc& alloc = Alloc()); -template -auto kruskal(IELR&& e, OELR&& t, CompareOp compare); +template > +auto kruskal(IELR&& e, OELR&& t, CompareOp compare, const Alloc& alloc = Alloc()); /* * Inplace Kruskal's Algorithm */ -template +template > requires permutable> -auto inplace_kruskal(IELR&& e, OELR&& t); +auto inplace_kruskal(IELR&& e, OELR&& t, const Alloc& alloc = Alloc()); -template +template > requires permutable> -auto inplace_kruskal(IELR&& e, OELR&& t, CompareOp compare); +auto inplace_kruskal(IELR&& e, OELR&& t, CompareOp compare, const Alloc& alloc = Alloc()); /* * Prim's Algorithm @@ -26,7 +30,8 @@ template (const remove_reference_t&, const edge_t&)>, - class CompareOp = less>> + class CompareOp = less>, + class Alloc = allocator> requires distance_fn_for && is_arithmetic_v> && predecessor_fn_for && @@ -37,4 +42,5 @@ auto prim(G&& g, WeightFn&& weight, PredecessorFn&& predecessor, WF&& weight_fn = [](const auto& gr, const edge_t& uv) { return edge_value(gr, uv); }, - CompareOp compare = less>()); + CompareOp compare = less>(), + const Alloc& alloc = Alloc()); diff --git a/D3128_Algorithms/src/tarjan_scc.hpp b/D3128_Algorithms/src/tarjan_scc.hpp index 39a17bf..a1f5dfe 100644 --- a/D3128_Algorithms/src/tarjan_scc.hpp +++ b/D3128_Algorithms/src/tarjan_scc.hpp @@ -1,6 +1,6 @@ /* * Tarjan's Strongly Connected Components */ -template +template > requires vertex_property_fn_for -size_t tarjan_scc(G&& g, ComponentFn&& component); +size_t tarjan_scc(G&& g, ComponentFn&& component, const Alloc& alloc = Alloc()); diff --git a/D3128_Algorithms/src/topological_sort.hpp b/D3128_Algorithms/src/topological_sort.hpp index 34fa7c6..c04a3b7 100644 --- a/D3128_Algorithms/src/topological_sort.hpp +++ b/D3128_Algorithms/src/topological_sort.hpp @@ -1,10 +1,12 @@ // Single-source topological sort -template +template > requires output_iterator> [[nodiscard]] bool -topological_sort(const G& g, const vertex_id_t& source, OutputIterator result); +topological_sort(const G& g, const vertex_id_t& source, OutputIterator result, + const Alloc& alloc = Alloc()); // Full-graph topological sort -template +template > requires output_iterator> -[[nodiscard]] bool topological_sort(const G& g, OutputIterator result); +[[nodiscard]] bool topological_sort(const G& g, OutputIterator result, + const Alloc& alloc = Alloc()); diff --git a/D3128_Algorithms/src/topological_sort_multi.hpp b/D3128_Algorithms/src/topological_sort_multi.hpp index 76ec7ba..788d0e9 100644 --- a/D3128_Algorithms/src/topological_sort_multi.hpp +++ b/D3128_Algorithms/src/topological_sort_multi.hpp @@ -1,4 +1,6 @@ -template +template > requires convertible_to, vertex_id_t> && output_iterator> -[[nodiscard]] bool topological_sort(const G& g, const Sources& sources, OutputIterator result); +[[nodiscard]] bool topological_sort(const G& g, const Sources& sources, OutputIterator result, + const Alloc& alloc = Alloc()); diff --git a/D3128_Algorithms/tex/algorithms.tex b/D3128_Algorithms/tex/algorithms.tex index 7aae31e..b95a861 100644 --- a/D3128_Algorithms/tex/algorithms.tex +++ b/D3128_Algorithms/tex/algorithms.tex @@ -492,6 +492,10 @@ \subsubsection{Multi-Source Breadth-First Search} \begin{itemize} \item \tcode{dijkstra_shortest_paths} provides extended functionality if \tcode{breadth_first_search} doesn't have enough capability. + \item The optional \lstinline{alloc} parameter supplies an allocator used for + the internal FIFO queue. Defaults to \tcode{std::allocator}. + Provide a custom allocator (e.g.~a pool allocator) to control the memory + used by the traversal queue. \end{itemize} %\pnum\errors \end{itemdescr} @@ -582,6 +586,10 @@ \subsubsection{Single Source Depth-First Search} \begin{itemize} \item Uses iterative DFS with explicit stack to avoid recursion-depth limits. \item Edge iterators are stored on the stack for $\mathcal{O}(1)$ resume after backtracking. + \item The optional \lstinline{alloc} parameter supplies an allocator used for + the internal DFS stack. Defaults to \tcode{std::allocator}. + Provide a custom allocator (e.g.~a pool allocator) to control the memory + used by the traversal stack. \end{itemize} %\pnum\errors \end{itemdescr} @@ -661,6 +669,10 @@ \subsubsection{Multi-Source Topological Sort} \begin{itemize} \item Duplicate sources do not affect the algorithm's complexity or correctness. \item The full-graph overload visits all vertices regardless of reachability from a single source. + \item The optional \lstinline{alloc} parameter supplies an allocator used for + the internal finish-order vector and DFS stack. Defaults to + \tcode{std::allocator}. All three overloads (single-source, + multi-source, full-graph) accept this parameter. \end{itemize} %\pnum\errors \end{itemdescr} @@ -846,6 +858,10 @@ \subsubsection{Dijkstra Shortest Paths} the same way (see §\textit{Vertex Property Function Concepts}). \item Pass \lstinline{_null_predecessor} as \lstinline{predecessor} when predecessor tracking is not needed (avoids storing results). + \item The optional \lstinline{alloc} parameter supplies an allocator used for + the internal priority queue. Defaults to \tcode{std::allocator}. + Provide a custom allocator (e.g.~a pool allocator) to control the memory + used by the priority queue during traversal. \end{itemize} %\pnum\errors \end{itemdescr} @@ -948,6 +964,10 @@ \subsubsection{Dijkstra Shortest Distances} \item \tcode{DistanceFn} must satisfy \tcode{distance_fn_for}. Wrap a \tcode{std::vector} or \tcode{std::unordered_map} with \tcode{container_value_fn} (see §\textit{Vertex Property Function Concepts}). + \item The optional \lstinline{alloc} parameter supplies an allocator used for + the internal priority queue. Defaults to \tcode{std::allocator}. + Provide a custom allocator (e.g.~a pool allocator) to control the memory + used by the priority queue during traversal. \end{itemize} %\pnum\errors \end{itemdescr} @@ -1568,6 +1588,9 @@ \subsection{Articulation Points} \lstinline{cut_vertices}. \item Disconnected graphs are handled correctly; the outer loop restarts DFS from each unvisited vertex. + \item The optional \lstinline{alloc} parameter supplies an allocator used for + the internal DFS stack and discovery/low-link arrays. Defaults to + \tcode{std::allocator}. \end{itemize} %\pnum\errors \end{itemdescr} @@ -1654,6 +1677,9 @@ \subsection{BiConnected Components} from each unvisited vertex. \item The implementation uses iterative DFS with stored edge iterators to avoid recursion-depth limits and $\mathcal{O}(\text{degree})$ re-scans on resume. + \item The optional \lstinline{alloc} parameter supplies an allocator used for + the internal DFS stack, edge stack, and discovery/low-link arrays. Defaults + to \tcode{std::allocator}. \end{itemize} %\pnum\errors \end{itemdescr} @@ -1680,7 +1706,7 @@ \subsection{Connected Components} { \small - \lstinputlisting[firstline=14,lastline=19]{D3128_Algorithms/src/connected_components.hpp} + \lstinputlisting[firstline=17,lastline=19]{D3128_Algorithms/src/connected_components.hpp} } \begin{itemdescr} @@ -1716,6 +1742,8 @@ \subsection{Connected Components} \item If the maximum component id is \lstinline{num_vertices(g)-1}, each vertex is the sole vertex in its own connected component. + \item The optional \lstinline{alloc} parameter supplies an allocator used for + the internal DFS stack. Defaults to \tcode{std::allocator}. \end{itemize} %\pnum\errors \end{itemdescr} @@ -1746,7 +1774,7 @@ \subsubsection{Kosaraju} \end{table} {\small - \lstinputlisting[firstline=32, lastline=41]{D3128_Algorithms/src/connected_components.hpp} + \lstinputlisting[firstline=35, lastline=43]{D3128_Algorithms/src/connected_components.hpp} } \begin{itemdescr} @@ -1787,6 +1815,9 @@ \subsubsection{Kosaraju} \item If the maximum component id is \lstinline{num_vertices(g)-1}, each vertex is the sole vertex in its own strongly connected component. + \item The optional \lstinline{alloc} parameter supplies an allocator used for + the internal finish-order vector and DFS stacks. Defaults to + \tcode{std::allocator}. \end{itemize} %\pnum\errors \end{itemdescr} @@ -1871,6 +1902,9 @@ \subsubsection{Tarjan's SCC} strongly connected component (the graph is strongly connected). \item If the return value equals \lstinline{num_vertices(g)}, every vertex is its own SCC (a DAG). + \item The optional \lstinline{alloc} parameter supplies an allocator used for + the internal DFS stack, SCC stack, and discovery/low-link arrays. Defaults + to \tcode{std::allocator}. \end{itemize} \end{itemdescr} @@ -2011,7 +2045,7 @@ \subsection{Kruskal Minimum Spanning Tree} \end{table} {\small - \lstinputlisting[firstline=4,lastline=8]{D3128_Algorithms/src/mst.hpp} + \lstinputlisting[firstline=4,lastline=10]{D3128_Algorithms/src/mst.hpp} } \begin{itemdescr} \pnum\mandates @@ -2042,7 +2076,9 @@ \subsection{Kruskal Minimum Spanning Tree} \item \textbf{Time:} $\mathcal{O}(|E|\log{|E|})$. \item \textbf{Space:} $\mathcal{O}(|E|+|V|)$ auxiliary --- edge copy and union-find. \end{itemize} - %\pnum\remarks + \pnum\remarks The optional \lstinline{alloc} parameter supplies an allocator used for + the internal disjoint-set (union-find) storage. Defaults to + \tcode{std::allocator}. %\pnum\errors \end{itemdescr} @@ -2068,7 +2104,7 @@ \subsection{Inplace Kruskal Minimum Spanning Tree} \end{table} {\small - \lstinputlisting[firstline=13,lastline=19]{D3128_Algorithms/src/mst.hpp} + \lstinputlisting[firstline=15,lastline=23]{D3128_Algorithms/src/mst.hpp} } \begin{itemdescr} \pnum\mandates @@ -2104,6 +2140,9 @@ \subsection{Inplace Kruskal Minimum Spanning Tree} \end{itemize} \pnum\remarks The input edge list is modified (sorted). If the caller needs to preserve the original order, use \lstinline{kruskal} instead. + The optional \lstinline{alloc} parameter supplies an allocator used for + the internal disjoint-set (union-find) storage. Defaults to + \tcode{std::allocator}. %\pnum\errors \end{itemdescr} @@ -2129,7 +2168,7 @@ \subsection{Prim Minimum Spanning Tree} \end{table} {\small - \lstinputlisting[firstline=24,lastline=40]{D3128_Algorithms/src/mst.hpp} + \lstinputlisting[firstline=28,lastline=46]{D3128_Algorithms/src/mst.hpp} } \begin{itemdescr} @@ -2186,6 +2225,9 @@ \subsection{Prim Minimum Spanning Tree} \end{itemize} \pnum\remarks Only produces a spanning tree for the connected component containing \lstinline{seed}. For disconnected graphs, call \lstinline{prim} once per component with a seed vertex from each component. + The optional \lstinline{alloc} parameter supplies an allocator used for + the internal priority queue (forwarded to \lstinline{dijkstra_shortest_paths}). + Defaults to \tcode{std::allocator}. %\pnum\errors \end{itemdescr}