Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_spanning_tree.H
Go to the documentation of this file.
1
2/*
3 Aleph_w
4
5 Data structures & Algorithms
6 version 2.0.0b
7 https://github.com/lrleon/Aleph-w
8
9 This file is part of Aleph-w library
10
11 Copyright (c) 2002-2026 Leandro Rabindranath Leon
12
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be included in all
21 copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 SOFTWARE.
30*/
31
32
52# ifndef TPL_SPANNING_TREE_H
53# define TPL_SPANNING_TREE_H
54
55# include <ah-graph-concepts.H>
56
57# include <tpl_graph.H>
58# include <tpl_graph_utils.H>
59# include <ah-errors.H>
60
61namespace Aleph {
62
112template <AlephGraph GT, ArcFilter<GT> SA = Dft_Show_Arc<GT>>
114{
115 SA sa;
116 GT * gptr = nullptr;
117 GT * tptr = nullptr;
118
119 // Recursive DFS helper to build the spanning tree
120 bool build_tree(typename GT::Node * gnode, typename GT::Arc * garc,
121 typename GT::Node * tnode)
122 {
123 // Mark node and arc as part of spanning tree
124 NODE_BITS(gnode).set_bit(Spanning_Tree, true);
125 ARC_BITS(garc).set_bit(Spanning_Tree, true);
126
127 // Create corresponding node in tree and establish mapping
128 auto tree_tgt_node = tptr->insert_node(gnode->get_info());
130
131 // Create corresponding arc in tree and establish mapping
132 auto tarc = tptr->insert_arc(tnode, tree_tgt_node, garc->get_info());
134
136
137 // Check if spanning tree is complete (all nodes covered)
139 return true;
140
141 // Invariant: tree must be acyclic (nodes > arcs)
143
144 // Explore adjacent nodes via DFS
146 i.has_curr() and tptr->get_num_nodes() < gptr->get_num_nodes();
147 i.next_ne())
148 {
149 auto arc = i.get_current_arc_ne();
150 if (IS_ARC_VISITED(arc, Spanning_Tree))
151 continue;
152
153 auto arc_tgt_node = i.get_tgt_node();
155 continue; // Target already visited via another arc
156
157 if (build_tree(arc_tgt_node, arc, tnode))
158 return true;
159 }
160
161 return false;
162 }
163
164 // Main algorithm entry point
165 bool build_tree(GT & g, typename GT::Node * gnode, GT & tree)
166 {
167 gptr = &g;
168 tptr = &tree;
169
170 // Reset all control bits for fresh traversal
171 gptr->reset_nodes();
172 gptr->reset_arcs();
173
174 // Ensure output tree is empty
176
177 // Mark starting node as visited
178 NODE_BITS(gnode).set_bit(Spanning_Tree, true);
179
180 // Create root node in tree and establish mapping
181 auto tnode = tree.insert_node(gnode->get_info());
183
184 // Explore all adjacent arcs via DFS
186 i.has_curr() and tptr->get_num_nodes() < gptr->get_num_nodes();
187 i.next_ne())
188 {
189 auto arc = i.get_current_arc_ne();
190 if (IS_ARC_VISITED(arc, Spanning_Tree))
191 continue;
192
193 auto arc_tgt_node = i.get_tgt_node();
195 continue; // Target already visited via another arc
196
197 if (build_tree(arc_tgt_node, arc, tnode))
198 return true;
199 }
200
201 return true;
202 }
203
204public:
205
211 Find_Depth_First_Spanning_Tree(SA arc_filter = SA()) : sa(arc_filter) { /* empty */ }
212
231 typename GT::Node * operator () (GT & g, GT & tree)
232 {
234 << "Find_Depth_First_Spanning_Tree: graph is empty";
235
236 auto start = g.get_first_node();
237 if (not build_tree(g, start, tree))
238 return nullptr;
239
240 return start;
241 }
242
260 typename GT::Node * operator () (GT & g, typename GT::Node * gnode, GT & tree)
261 {
262 ah_invalid_argument_if(gnode == nullptr)
263 << "Find_Depth_First_Spanning_Tree: source node cannot be null";
264
265 this->build_tree(g, gnode, tree);
266 return static_cast<typename GT::Node *>(NODE_COOKIE(gnode));
267 }
268};
269
270
315template <AlephGraph GT, ArcFilter<GT> SA = Dft_Show_Arc<GT>>
317{
318 SA sa;
319
320 // Main BFS algorithm to build spanning tree
321 void build_tree(GT & g, typename GT::Node * gp, GT & tree)
322 {
323 // Reset control bits for fresh traversal
326
327 // Ensure output tree is empty
328 clear_graph(tree);
329
330 // Create root node in tree and establish mapping
331 auto tp = tree.insert_node(gp->get_info());
332 GT::map_nodes(gp, tp);
333
334 // Initialize queue with arcs adjacent to starting node
336 for (Node_Arc_Iterator<GT, SA> i(gp, sa); i.has_curr(); i.next_ne())
337 q.put(i.get_current_arc_ne());
338
339 // Mark starting node as visited
340 NODE_BITS(gp).set_bit(Spanning_Tree, true);
341
342 // BFS loop
343 while (not q.is_empty())
344 {
345 auto garc = q.get();
346 ARC_BITS(garc).set_bit(Spanning_Tree, true);
347 auto gsrc = g.get_src_node(garc);
348 auto gtgt = g.get_tgt_node(garc);
349
350 // Skip if both endpoints already visited
353 continue;
354
355 // Ensure gsrc is the visited node and gtgt is the new one
357 std::swap(gsrc, gtgt);
358
359 auto tsrc = mapped_node<GT>(gsrc);
360 NODE_BITS(gtgt).set_bit(Spanning_Tree, true);
361
362 // Create new node in tree and establish mapping
363 auto ttgt = tree.insert_node(gtgt->get_info());
365
366 // Create new arc in tree and establish mapping
367 auto tarc = tree.insert_arc(tsrc, ttgt, garc->get_info());
369
370 // Check if spanning tree is complete
371 if (tree.get_num_nodes() == g.get_num_nodes())
372 break;
373
374 // Enqueue arcs adjacent to newly added node
375 for (Node_Arc_Iterator<GT, SA> i(gtgt, sa); i.has_curr(); i.next_ne())
376 {
377 auto current_arc = i.get_current_arc_ne();
378 if (IS_ARC_VISITED(current_arc, Spanning_Tree))
379 continue;
380
381 // Skip arcs where both endpoints are already visited
382 if (IS_NODE_VISITED(g.get_src_node(current_arc), Spanning_Tree) and
384 continue;
385 q.put(current_arc);
386 }
387 }
388 }
389
390public:
391
397 Find_Breadth_First_Spanning_Tree(SA arc_filter = SA()) : sa(arc_filter) { /* empty */ }
398
416 void operator () (GT & g, typename GT::Node * gnode, GT & tree)
417 {
418 ah_invalid_argument_if(gnode == nullptr)
419 << "Find_Breadth_First_Spanning_Tree: source node cannot be null";
420
421 this->build_tree(g, gnode, tree);
422 }
423
436 typename GT::Node * operator () (GT & g, GT & tree)
437 {
439 << "Find_Breadth_First_Spanning_Tree: graph is empty";
440
441 auto start = g.get_first_node();
442 this->build_tree(g, start, tree);
443 return static_cast<typename GT::Node *>(NODE_COOKIE(start));
444 }
445};
446
466template <AlephGraph GT>
468{
469public:
470
484
496 {
497 ah_invalid_argument_if(arcs == nullptr)
498 << "Build_Spanning_Tree: arcs array cannot be null";
500 }
501};
502
503} // end namespace Aleph
504
505# endif // TPL_SPANNING_TREE_H
Exception handling system with formatted messages for Aleph-w.
#define ah_domain_error_if(C)
Throws std::domain_error if condition holds.
Definition ah-errors.H:527
#define ah_invalid_argument_if(C)
Throws std::invalid_argument if condition holds.
Definition ah-errors.H:644
C++20 concepts for the protocol shared by graph algorithms.
EepicNode< long > * build_tree()
Definition btreepic.C:1435
Build a spanning tree from an array of arcs.
GT operator()(const DynArray< typename GT::Arc * > &arcs) const
Construct spanning tree from array of arc pointers.
Dynamic queue of elements of generic type T based on single linked list.
T & put(const T &data)
The type of element.
T get()
Remove the oldest item of the queue.
bool is_empty() const noexcept
Return true if this is empty.
void next_ne() noexcept
Advances the iterator to the next filtered element (noexcept version).
Compute a breadth-first spanning tree of a graph.
void build_tree(GT &g, typename GT::Node *gp, GT &tree)
void operator()(GT &g, typename GT::Node *gnode, GT &tree)
Build a breadth-first spanning tree starting from a specific node.
Find_Breadth_First_Spanning_Tree(SA arc_filter=SA())
Construct a BFS spanning tree builder with optional arc filter.
Compute a depth-first spanning tree of a graph.
GT::Node * operator()(GT &g, GT &tree)
Build a depth-first spanning tree starting from the first node.
Find_Depth_First_Spanning_Tree(SA arc_filter=SA())
Construct a DFS spanning tree builder with optional arc filter.
bool build_tree(typename GT::Node *gnode, typename GT::Arc *garc, typename GT::Node *tnode)
bool build_tree(GT &g, typename GT::Node *gnode, GT &tree)
Node * get_first_node() const
Return any node in the graph.
Definition tpl_graph.H:577
virtual Node * insert_node(Node *node) noexcept
Insertion of a node already allocated.
Definition tpl_graph.H:525
Arc * insert_arc(Node *src_node, Node *tgt_node, void *a)
Definition tpl_graph.H:605
void reset_bit_nodes(int bit) const noexcept
Reset bit to zero for all the nodes of graph.
Definition graph-dry.H:1088
void reset_arcs() const
Reset all the arcs of graph (the control bits, the state, the counter and the cookie)
Definition graph-dry.H:975
Node * get_src_node(Arc *arc) const noexcept
Return the source node of arc (only for directed graphs)
Definition graph-dry.H:779
constexpr size_t get_num_nodes() const noexcept
Return the total of nodes of graph.
Definition graph-dry.H:737
static void map_arcs(A1 *p, A2 *q) noexcept
Map the arcs through their cookies.
Definition graph-dry.H:1074
void reset_bit_arcs(int bit) const noexcept
Reset bit to zero for all the arcs of graph.
Definition graph-dry.H:1094
constexpr size_t get_num_arcs() const noexcept
Definition graph-dry.H:826
void reset_nodes() const
Reset all the nodes of graph (the control bits, the state, the counter and the cookie)
Definition graph-dry.H:968
Node * get_tgt_node(Arc *arc) const noexcept
Return the target node of arc (only for directed graphs)
Definition graph-dry.H:785
static void map_nodes(N1 *p, N2 *q) noexcept
Map the nodes through their cookies.
Definition graph-dry.H:1043
DynArray< Graph::Arc * > arcs
Definition graphpic.C:408
#define IS_NODE_VISITED(p, bit)
Determine whether the control bit is set or not to one.
#define ARC_BITS(p)
Return the control bits of arc p.
#define NODE_COOKIE(p)
Return the node cookie
void clear_graph(GT &g) noexcept
Clean a graph: all its nodes and arcs are removed and freed.
Definition tpl_graph.H:3659
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
Definition Blossom.H:466
#define IS_ARC_VISITED(p, bit)
Determine whether the bit field is or not set to one.
#define NODE_BITS(p)
Get the control bits of a node.
@ Spanning_Tree
Definition aleph-graph.H:79
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
and
Check uniqueness with explicit hash + equality functors.
Filtered iterator of adjacent arcs of a node.
Definition tpl_graph.H:1120
Generic graph and digraph implementations.
Utility algorithms and operations for graphs.