Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
bfs_dfs_example.C
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
112#include <iostream>
113#include <iomanip>
114#include <string>
115#include <vector>
116#include <tpl_graph.H>
117#include <graph-traverse.H>
118#include <tpl_components.H>
119#include <tpl_find_path.H>
120#include <tclap/CmdLine.h>
121
122using namespace std;
123using namespace Aleph;
124
125// Graph types
129
144{
145 Graph g;
146
147 auto alice = g.insert_node("Alice");
148 auto bob = g.insert_node("Bob");
149 auto charlie = g.insert_node("Charlie");
150 auto diana = g.insert_node("Diana");
151 auto eve = g.insert_node("Eve");
152 auto frank = g.insert_node("Frank");
153 auto grace = g.insert_node("Grace");
154 auto henry = g.insert_node("Henry");
155
156 // Friendships (undirected)
157 g.insert_arc(alice, bob);
160 g.insert_arc(bob, diana);
162 g.insert_arc(diana, eve);
166
167 return g;
168}
169
182{
183 Graph g;
184
185 vector<Graph::Node*> nodes;
186 for (int i = 1; i <= 10; ++i)
187 nodes.push_back(g.insert_node(to_string(i)));
188
189 // Tree structure
190 g.insert_arc(nodes[0], nodes[1]); // 1-2
191 g.insert_arc(nodes[0], nodes[2]); // 1-3
192 g.insert_arc(nodes[0], nodes[3]); // 1-4
193 g.insert_arc(nodes[1], nodes[4]); // 2-5
194 g.insert_arc(nodes[1], nodes[5]); // 2-6
195 g.insert_arc(nodes[3], nodes[6]); // 4-7
196 g.insert_arc(nodes[4], nodes[7]); // 5-8
197 g.insert_arc(nodes[4], nodes[8]); // 5-9
198 g.insert_arc(nodes[4], nodes[9]); // 5-10
199
200 return g;
201}
202
206Graph::Node* find_node(Graph& g, const string& name)
207{
208 for (auto it = g.get_node_it(); it.has_curr(); it.next())
209 if (it.get_curr()->get_info() == name)
210 return it.get_curr();
211 return nullptr;
212}
213
217void print_graph(Graph& g, const string& title)
218{
219 cout << "\n=== " << title << " ===" << endl;
220 cout << "Nodes: " << g.get_num_nodes() << endl;
221 cout << "Edges: " << g.get_num_arcs() << endl;
222
223 cout << "\nAdjacency list:" << endl;
224 for (auto nit = g.get_node_it(); nit.has_curr(); nit.next())
225 {
226 auto* node = nit.get_curr();
227 cout << " " << node->get_info() << " -- ";
228
229 bool first = true;
230 for (Node_Arc_Iterator<Graph> ait(node); ait.has_curr(); ait.next())
231 {
232 auto* arc = ait.get_curr();
233 auto* neighbor = g.get_connected_node(arc, node);
234 if (not first) cout << ", ";
235 cout << neighbor->get_info();
236 first = false;
237 }
238 cout << endl;
239 }
240}
241
245void demo_bfs(Graph& g, Graph::Node* start)
246{
247 cout << "\n--- BFS (Breadth-First Search) ---" << endl;
248 cout << "Uses: Queue (FIFO)" << endl;
249 cout << "Explores: Level by level" << endl;
250 cout << "Starting from: " << start->get_info() << endl;
251
252 cout << "\nVisit order: ";
253
254 int visit_num = 0;
255 auto visitor = [&visit_num](Graph::Node* node) {
256 if (visit_num > 0) cout << " -> ";
257 cout << node->get_info();
258 ++visit_num;
259 return true; // Continue traversal
260 };
261
262 // BFS uses DynListQueue
264 size_t visited = bfs(start, visitor);
265
266 cout << endl;
267 cout << "Total nodes visited: " << visited << endl;
268}
269
273void demo_dfs(Graph& g, Graph::Node* start)
274{
275 cout << "\n--- DFS (Depth-First Search) ---" << endl;
276 cout << "Uses: Stack (LIFO)" << endl;
277 cout << "Explores: As deep as possible first" << endl;
278 cout << "Starting from: " << start->get_info() << endl;
279
280 cout << "\nVisit order: ";
281
282 int visit_num = 0;
283 auto visitor = [&visit_num](Graph::Node* node) {
284 if (visit_num > 0) cout << " -> ";
285 cout << node->get_info();
286 ++visit_num;
287 return true;
288 };
289
290 // DFS uses DynListStack
292 size_t visited = dfs(start, visitor);
293
294 cout << endl;
295 cout << "Total nodes visited: " << visited << endl;
296}
297
302{
303 cout << "\n" << string(60, '=') << endl;
304 cout << "BFS vs DFS: Side-by-Side Comparison" << endl;
305 cout << string(60, '=') << endl;
306
308 print_graph(g, "Tree Graph");
309
310 auto* root = find_node(g, "1");
311
312 demo_bfs(g, root);
313 demo_dfs(g, root);
314
315 cout << "\n--- Analysis ---" << endl;
316 cout << "BFS visits nodes level by level: 1, then 2-3-4, then 5-6-7, etc." << endl;
317 cout << "DFS explores one branch completely before backtracking." << endl;
318}
319
324{
325 cout << "\n" << string(60, '=') << endl;
326 cout << "Practical Example: Degrees of Separation (BFS)" << endl;
327 cout << string(60, '=') << endl;
328
330 print_graph(g, "Social Network");
331
332 auto* alice = find_node(g, "Alice");
333 auto* henry = find_node(g, "Henry");
334
335 cout << "\nFinding shortest path from Alice to Henry..." << endl;
336
337 // Use BFS to find shortest path
340
341 if (path.size() > 0)
342 {
343 cout << "Path found! Degrees of separation: " << (path.size() - 1) << endl;
344 cout << "Connection: ";
345
346 bool first = true;
347 for (auto it = path.get_it(); it.has_curr(); it.next())
348 {
349 if (not first) cout << " -> ";
350 cout << it.get_curr()->get_info();
351 first = false;
352 }
353 cout << endl;
354 }
355 else
356 {
357 cout << "No path found!" << endl;
358 }
359
360 cout << "\nNote: BFS guarantees finding the shortest path (fewest edges)." << endl;
361}
362
367{
368 cout << "\n" << string(60, '=') << endl;
369 cout << "Practical Example: Finding Any Path (DFS)" << endl;
370 cout << string(60, '=') << endl;
371
373
374 auto* alice = find_node(g, "Alice");
375 auto* henry = find_node(g, "Henry");
376
377 cout << "\nFinding a path (any path) from Alice to Henry using DFS..." << endl;
378
381
382 if (path.size() > 0)
383 {
384 cout << "Path found (may not be shortest): " << endl;
385 cout << "Length: " << (path.size() - 1) << " edges" << endl;
386 cout << "Path: ";
387
388 bool first = true;
389 for (auto it = path.get_it(); it.has_curr(); it.next())
390 {
391 if (not first) cout << " -> ";
392 cout << it.get_curr()->get_info();
393 first = false;
394 }
395 cout << endl;
396 }
397
398 cout << "\nNote: DFS doesn't guarantee shortest path, but uses less memory" << endl;
399 cout << " on deep graphs and can be useful for exploring all possibilities." << endl;
400}
401
406{
407 cout << "\n" << string(60, '=') << endl;
408 cout << "Early Termination: Stop When Target Found" << endl;
409 cout << string(60, '=') << endl;
410
412
413 auto* alice = find_node(g, "Alice");
414 string target = "Eve";
415
416 cout << "\nSearching for '" << target << "' starting from 'Alice'..." << endl;
417
418 Graph::Node* found_node = nullptr;
419 int nodes_visited = 0;
420
421 auto search_visitor = [&](Graph::Node* node) {
423 cout << " Visiting: " << node->get_info() << endl;
424
425 if (node->get_info() == target)
426 {
427 found_node = node;
428 return false; // Stop traversal
429 }
430 return true; // Continue
431 };
432
433 cout << "\nUsing BFS:" << endl;
434 found_node = nullptr;
435 nodes_visited = 0;
437 bfs(alice, search_visitor);
438 cout << "Nodes visited before finding '" << target << "': " << nodes_visited << endl;
439
440 cout << "\nUsing DFS:" << endl;
441 found_node = nullptr;
442 nodes_visited = 0;
444 dfs(alice, search_visitor);
445 cout << "Nodes visited before finding '" << target << "': " << nodes_visited << endl;
446
447 cout << "\nNote: BFS may find closer targets faster, DFS may explore more." << endl;
448}
449
454{
455 cout << "\n" << string(60, '=') << endl;
456 cout << "Practical Example: Finding Connected Components" << endl;
457 cout << string(60, '=') << endl;
458
459 Graph g;
460
461 // Component 1: A-B-C
462 auto a = g.insert_node("A");
463 auto b = g.insert_node("B");
464 auto c = g.insert_node("C");
465 g.insert_arc(a, b);
466 g.insert_arc(b, c);
467
468 // Component 2: D-E
469 auto d = g.insert_node("D");
470 auto e = g.insert_node("E");
471 g.insert_arc(d, e);
472
473 // Component 3: F (isolated)
474 g.insert_node("F");
475
476 print_graph(g, "Graph with Multiple Components");
477
478 cout << "\nFinding connected components using Unconnected_Components..." << endl;
479
482 cc(g, components);
483
484 int component_num = 0;
485 for (auto & comp : components)
486 {
488 cout << "\nComponent " << component_num << ": ";
489
490 bool first = true;
491 for (auto nit = comp.get_node_it(); nit.has_curr(); nit.next_ne())
492 {
493 if (not first) cout << ", ";
494 cout << nit.get_curr()->get_info();
495 first = false;
496 }
497 cout << endl;
498 }
499
500 cout << "\nTotal components: " << components.size() << endl;
501}
502
503int main(int argc, char* argv[])
504{
505 try
506 {
507 TCLAP::CmdLine cmd("BFS/DFS Graph Traversal Example", ' ', "1.0");
508
509 TCLAP::SwitchArg compareArg("c", "compare",
510 "Compare BFS and DFS on same graph", false);
511 TCLAP::SwitchArg degreesArg("d", "degrees",
512 "Show degrees of separation example", false);
513 TCLAP::SwitchArg pathArg("p", "path",
514 "Show any path example (DFS)", false);
515 TCLAP::SwitchArg earlyArg("e", "early",
516 "Show early termination example", false);
517 TCLAP::SwitchArg compArg("o", "components",
518 "Show connected components example", false);
519 TCLAP::SwitchArg allArg("a", "all",
520 "Run all demos", false);
521
522 cmd.add(compareArg);
523 cmd.add(degreesArg);
524 cmd.add(pathArg);
525 cmd.add(earlyArg);
526 cmd.add(compArg);
527 cmd.add(allArg);
528
529 cmd.parse(argc, argv);
530
531 bool runCompare = compareArg.getValue();
532 bool runDegrees = degreesArg.getValue();
533 bool runPath = pathArg.getValue();
534 bool runEarly = earlyArg.getValue();
535 bool runComp = compArg.getValue();
536 bool runAll = allArg.getValue();
537
540 runAll = true;
541
542 cout << "=== Graph Traversal: BFS vs DFS ===" << endl;
543 cout << "BFS: Breadth-First (Queue) - Finds shortest paths" << endl;
544 cout << "DFS: Depth-First (Stack) - Explores deeply first" << endl;
545
546 if (runAll or runCompare)
548
549 if (runAll or runDegrees)
551
552 if (runAll or runPath)
554
555 if (runAll or runEarly)
557
558 if (runAll or runComp)
560
561 cout << "\n=== Summary ===" << endl;
562 cout << "BFS: Use when shortest path matters (unweighted graphs)" << endl;
563 cout << "DFS: Use for topological sort, cycle detection, or when any path suffices" << endl;
564 cout << "Both: O(V + E) time complexity" << endl;
565
566 return 0;
567 }
568 catch (TCLAP::ArgException& e)
569 {
570 cerr << "Error: " << e.error() << " for arg " << e.argId() << endl;
571 return 1;
572 }
573}
574
int main()
WeightedDigraph::Node Node
WeightedDigraph::Arc Arc
void demo_dfs(Graph &g, Graph::Node *start)
Demonstrate DFS traversal.
Graph build_social_network()
Build a sample social network graph.
void demo_any_path()
Practical example: Finding any path (DFS)
void demo_bfs(Graph &g, Graph::Node *start)
Demonstrate BFS traversal.
void print_graph(Graph &g, const string &title)
Print graph structure.
void demo_connected_components()
Demonstrate finding connected components.
void demo_comparison()
Compare BFS and DFS on the same graph.
Graph build_tree_graph()
Build a tree-like graph for clear traversal comparison.
void demo_early_termination()
Demonstrate early termination.
Graph::Node * find_node(Graph &g, const string &name)
Find a node by name.
void demo_degrees_of_separation()
Practical example: Finding degrees of separation.
Dynamic queue of elements of generic type T based on single linked list.
Dynamic stack of elements of generic type T based on a singly linked list.
Dynamic singly linked list with functional programming support.
Definition htlist.H:1423
Busca en amplitud un camino entre un par de nodos.
Busca en profundidad un camino entre un par de nodos.
size_t size() const noexcept
Count the number of elements of the list.
Definition htlist.H:1319
virtual Node * insert_node(Node *node) noexcept
Insertion of a node already allocated.
Definition tpl_graph.H:524
Node Node
The graph type.
Definition tpl_graph.H:432
Arc * insert_arc(Node *src_node, Node *tgt_node, void *a)
Definition tpl_graph.H:604
Path on a graph.
Definition tpl_graph.H:2669
size_t size() const noexcept
Return the path length in nodes.
Definition tpl_graph.H:2807
Iterator get_it() const
Returns an iterator on the path.
Definition tpl_graph.H:3321
Compute the connected components of a graph.
constexpr size_t get_num_nodes() const noexcept
Return the total of nodes of graph.
Definition graph-dry.H:695
Node * get_connected_node(Arc *arc, Node *node) const noexcept
Return the adjacent node to node through arc.
Definition graph-dry.H:772
constexpr size_t get_num_arcs() const noexcept
Definition graph-dry.H:778
auto get_node_it() const noexcept
Obtains an iterator to the nodes of graph.
Definition graph-dry.H:2780
Traverse a graph depth-first or breadth-first and execute a visit function.
__gmp_expr< T, __gmp_binary_expr< __gmp_expr< T, U >, unsigned long int, __gmp_root_function > > root(const __gmp_expr< T, U > &expr, unsigned long int l)
Definition gmpfrxx.h:4060
Graph traversal algorithms (DFS, BFS).
DynArray< Graph::Node * > nodes
Definition graphpic.C:406
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
std::string to_string(const time_t t, const std::string &format)
Format a time_t value into a string using format.
Definition ah-date.H:140
DynList< T > maps(const C &c, Op op)
Classic map operation.
STL namespace.
Arc of graph implemented with double-linked adjacency lists.
Definition tpl_graph.H:222
Node belonging to a graph implemented with a double linked adjacency list.
Definition tpl_graph.H:121
Filtered iterator of adjacent arcs of a node.
Definition tpl_graph.H:1119
Graph connectivity and connected components.
Path finding algorithms in graphs.
Generic graph and digraph implementations.