Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
graph_components_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
189#include <iostream>
190#include <string>
191#include <cstring>
192#include <tpl_graph.H>
193#include <tpl_components.H>
194#include <tpl_spanning_tree.H>
196#include <Tarjan.H>
197
198using namespace std;
199using namespace Aleph;
200
201static bool has_flag(int argc, char* argv[], const char* flag)
202{
203 for (int i = 1; i < argc; ++i)
204 if (std::strcmp(argv[i], flag) == 0)
205 return true;
206 return false;
207}
208
209static void usage(const char* prog)
210{
211 cout << "Usage: " << prog
212 << " [--components] [--scc] [--spanning-tree] [--network-analysis] [--all] [--help]\n";
213 cout << "\nIf no flags are given, all demos are executed.\n";
214}
215
216// Graph types
219
220// =============================================================================
221// Helper functions
222// =============================================================================
223
224template <class GT>
225typename GT::Node* find_or_create(GT& g, const string& name)
226{
227 for (auto it = g.get_node_it(); it.has_curr(); it.next_ne())
228 if (it.get_curr()->get_info() == name)
229 return it.get_curr();
230 return g.insert_node(name);
231}
232
233template <class GT>
234void add_edge(GT& g, const string& src, const string& tgt, int weight = 1)
235{
236 auto s = find_or_create(g, src);
237 auto t = find_or_create(g, tgt);
238 g.insert_arc(s, t, weight);
239}
240
241template <class GT>
242void print_graph(GT& g, const string& title)
243{
244 cout << title << ":\n";
245 cout << " Vertices: ";
246 for (auto it = g.get_node_it(); it.has_curr(); it.next_ne())
247 cout << it.get_curr()->get_info() << " ";
248 cout << "\n Edges:\n";
249 for (auto it = g.get_arc_it(); it.has_curr(); it.next_ne()) {
250 auto arc = it.get_curr();
251 cout << " " << g.get_src_node(arc)->get_info()
252 << " → " << g.get_tgt_node(arc)->get_info() << "\n";
253 }
254 cout << "\n";
255}
256
257// =============================================================================
258// Example 1: Connected Components (Undirected Graph)
259// =============================================================================
260
262{
263 cout << "\n";
264 cout << "╔══════════════════════════════════════════════════════════════════╗\n";
265 cout << "║ EXAMPLE 1: Connected Components (Undirected) ║\n";
266 cout << "╚══════════════════════════════════════════════════════════════════╝\n\n";
267
268 cout << "A connected component is a maximal set of vertices where\n";
269 cout << "every pair of vertices is connected by a path.\n\n";
270
271 UGraph g;
272
273 // Component 1: A-B-C
274 add_edge(g, "A", "B");
275 add_edge(g, "B", "C");
276 add_edge(g, "A", "C");
277
278 // Component 2: D-E
279 add_edge(g, "D", "E");
280
281 // Component 3: F (isolated)
282 find_or_create(g, "F");
283
284 // Component 4: G-H-I
285 add_edge(g, "G", "H");
286 add_edge(g, "H", "I");
287
288 print_graph(g, "Graph with 4 components");
289
290 // Find connected components using Unconnected_Components
293 uc(g, components);
294
295 cout << "Found " << components.size() << " connected components:\n\n";
296
297 int i = 1;
298 for (auto& comp : components) {
299 cout << " Component " << i++ << ": ";
300 for (auto it = comp.get_node_it(); it.has_curr(); it.next_ne())
301 cout << it.get_curr()->get_info() << " ";
302 cout << "(size: " << comp.get_num_nodes() << ")\n";
303 }
304
305 cout << "\n--- Testing connectivity ---\n\n";
306
307 // Test connectivity using test_connectivity function
309 bool is_connected = test_conn(g);
310
311 cout << " Graph is fully connected: " << (is_connected ? "YES" : "NO") << "\n";
312 cout << " Number of components: " << components.size() << "\n";
313}
314
315// =============================================================================
316// Example 2: Strongly Connected Components (Directed Graph)
317// =============================================================================
318
320{
321 cout << "\n";
322 cout << "╔══════════════════════════════════════════════════════════════════╗\n";
323 cout << "║ EXAMPLE 2: Strongly Connected Components (Directed) ║\n";
324 cout << "╚══════════════════════════════════════════════════════════════════╝\n\n";
325
326 cout << "A strongly connected component (SCC) is a maximal set where\n";
327 cout << "every vertex can reach every other vertex (bidirectional paths).\n\n";
328
329 DGraph g;
330
331 // SCC 1: A ↔ B ↔ C (cycle)
332 add_edge(g, "A", "B");
333 add_edge(g, "B", "C");
334 add_edge(g, "C", "A");
335
336 // SCC 2: D ↔ E (cycle)
337 add_edge(g, "D", "E");
338 add_edge(g, "E", "D");
339
340 // SCC 3: F (single node)
341 find_or_create(g, "F");
342
343 // Cross-component edges
344 add_edge(g, "C", "D");
345 add_edge(g, "E", "F");
346
347 print_graph(g, "Directed graph");
348
349 // Using Tarjan's algorithm
351 auto sccs = tarjan(g); // Returns DynList<DynList<Node*>>
352
353 cout << "Tarjan's Algorithm found " << sccs.size() << " SCCs:\n\n";
354
355 int i = 1;
356 for (auto& scc : sccs) {
357 cout << " SCC " << i++ << ": ";
358 for (auto node : scc)
359 cout << node->get_info() << " ";
360 cout << "\n";
361 }
362
363 // Check if graph has cycles
364 cout << "\n--- Cycle analysis ---\n\n";
365 cout << " Graph has cycles: " << (tarjan.has_cycle(g) ? "YES" : "NO") << "\n";
366 cout << " Graph is a DAG: " << (tarjan.is_dag(g) ? "YES" : "NO") << "\n";
367
368 cout << "\n--- Why SCCs matter ---\n\n";
369 cout << " • Compiler optimization: basic blocks\n";
370 cout << " • Web crawling: identify tightly connected pages\n";
371 cout << " • Social networks: find communities\n";
372 cout << " • 2-SAT problem solving\n";
373}
374
375// =============================================================================
376// Example 3: Spanning Tree
377// =============================================================================
378
380{
381 cout << "\n";
382 cout << "╔══════════════════════════════════════════════════════════════════╗\n";
383 cout << "║ EXAMPLE 3: Spanning Tree ║\n";
384 cout << "╚══════════════════════════════════════════════════════════════════╝\n\n";
385
386 cout << "A spanning tree connects all vertices using exactly V-1 edges.\n";
387 cout << "It contains no cycles and forms a tree structure.\n\n";
388
389 UGraph g;
390
391 // Create a connected graph
392 add_edge(g, "A", "B");
393 add_edge(g, "A", "C");
394 add_edge(g, "B", "C");
395 add_edge(g, "B", "D");
396 add_edge(g, "C", "D");
397 add_edge(g, "C", "E");
398 add_edge(g, "D", "E");
399
400 cout << "Original graph:\n";
401 cout << " Vertices: " << g.get_num_nodes() << "\n";
402 cout << " Edges: " << g.get_num_arcs() << "\n\n";
403
404 // Build spanning tree using DFS
405 UGraph tree;
407
408 auto start = find_or_create(g, "A");
409 dfs_tree(g, start, tree);
410
411 cout << "DFS Spanning Tree:\n";
412 cout << " Vertices: " << tree.get_num_nodes() << "\n";
413 cout << " Edges: " << tree.get_num_arcs() << "\n";
414 cout << " Tree edges:\n";
415 for (auto it = tree.get_arc_it(); it.has_curr(); it.next_ne()) {
416 auto arc = it.get_curr();
417 cout << " " << tree.get_src_node(arc)->get_info()
418 << " — " << tree.get_tgt_node(arc)->get_info() << "\n";
419 }
420
421 cout << "\n--- Properties of spanning tree ---\n\n";
422 cout << " • Connects all " << tree.get_num_nodes() << " vertices\n";
423 cout << " • Uses exactly " << tree.get_num_arcs() << " edges (V-1)\n";
424 cout << " • Contains no cycles\n";
425 cout << " • Unique path between any two vertices\n";
426}
427
428// =============================================================================
429// Example 4: Practical Application - Network Analysis
430// =============================================================================
431
433{
434 cout << "\n";
435 cout << "╔══════════════════════════════════════════════════════════════════╗\n";
436 cout << "║ EXAMPLE 4: Network Analysis Application ║\n";
437 cout << "╚══════════════════════════════════════════════════════════════════╝\n\n";
438
439 cout << "Scenario: Analyzing a computer network for redundancy.\n\n";
440
442
443 // Core network (highly connected)
444 add_edge(network, "Server1", "Server2");
445 add_edge(network, "Server2", "Server3");
446 add_edge(network, "Server3", "Server1");
447 add_edge(network, "Server1", "Router");
448 add_edge(network, "Server2", "Router");
449
450 // Branch office (separate component)
451 add_edge(network, "Branch1", "Branch2");
452
453 // Remote worker (isolated)
454 find_or_create(network, "Remote");
455
456 // Analyze components
460
461 cout << "Network analysis results:\n\n";
462 cout << " Total devices: " << network.get_num_nodes() << "\n";
463 cout << " Network segments: " << components.size() << "\n\n";
464
465 int segment = 1;
466 for (auto& comp : components) {
467 cout << " Segment " << segment++ << ":\n";
468 cout << " Devices: ";
469 for (auto it = comp.get_node_it(); it.has_curr(); it.next_ne())
470 cout << it.get_curr()->get_info() << " ";
471 cout << "\n";
472 cout << " Connections: " << comp.get_num_arcs() << "\n";
473
474 // Check if segment is a single point of failure
475 if (comp.get_num_nodes() > 1 && comp.get_num_arcs() == comp.get_num_nodes() - 1)
476 cout << " ⚠️ No redundancy (tree structure)\n";
477 else if (comp.get_num_arcs() > comp.get_num_nodes() - 1)
478 cout << " ✓ Has redundancy (multiple paths)\n";
479 else
480 cout << " • Single device\n";
481 cout << "\n";
482 }
483
484 cout << "Recommendation: Connect segments for full network connectivity.\n";
485}
486
487// =============================================================================
488// Main
489// =============================================================================
490
491int main(int argc, char* argv[])
492{
493 if (has_flag(argc, argv, "--help"))
494 {
495 usage(argv[0]);
496 return 0;
497 }
498
499 const bool run_all = has_flag(argc, argv, "--all") || argc == 1;
500 const bool run_components = run_all || has_flag(argc, argv, "--components");
501 const bool run_scc = run_all || has_flag(argc, argv, "--scc");
502 const bool run_spanning = run_all || has_flag(argc, argv, "--spanning-tree");
503 const bool run_network = run_all || has_flag(argc, argv, "--network-analysis");
504
505 cout << "\n";
506 cout << "╔══════════════════════════════════════════════════════════════════╗\n";
507 cout << "║ Graph Connectivity Analysis in Aleph-w Library ║\n";
508 cout << "║ ║\n";
509 cout << "║ Aleph-w Library - https://github.com/lrleon/Aleph-w ║\n";
510 cout << "╚══════════════════════════════════════════════════════════════════╝\n";
511
512 if (run_components)
514 if (run_scc)
516 if (run_spanning)
518 if (run_network)
520
522 {
523 usage(argv[0]);
524 return 1;
525 }
526
527 cout << "\n";
528 cout << "╔══════════════════════════════════════════════════════════════════╗\n";
529 cout << "║ Summary ║\n";
530 cout << "╠══════════════════════════════════════════════════════════════════╣\n";
531 cout << "║ Unconnected_Components: Find connected components (undirected) ║\n";
532 cout << "║ Tarjan_Connected: Find SCCs (directed) - O(V+E) ║\n";
533 cout << "║ Find_DFS_Spanning_Tree: Build spanning tree via DFS ║\n";
534 cout << "║ Find_BFS_Spanning_Tree: Build spanning tree via BFS ║\n";
535 cout << "║ Test_Connectivity: Check if graph is connected ║\n";
536 cout << "║ ║\n";
537 cout << "║ All algorithms run in O(V + E) time complexity. ║\n";
538 cout << "╚══════════════════════════════════════════════════════════════════╝\n\n";
539
540 return 0;
541}
Tarjan's algorithm for strongly connected components.
int main()
Generic directed graph (digraph) wrapper template.
Definition graph-dry.H:3848
Dynamic singly linked list with functional programming support.
Definition htlist.H:1423
Compute a depth-first spanning tree of a graph.
size_t size() const noexcept
Count the number of elements of the list.
Definition htlist.H:1319
Graph implemented with double-linked adjacency lists.
Definition tpl_graph.H:428
virtual Node * insert_node(Node *node) noexcept
Insertion of a node already allocated.
Definition tpl_graph.H:524
Arc * insert_arc(Node *src_node, Node *tgt_node, void *a)
Definition tpl_graph.H:604
Computes strongly connected components (SCCs) in a directed graph using Tarjan's algorithm.
Definition Tarjan.H:171
Compute the connected components of a graph.
auto get_arc_it() const noexcept
Obtains an iterator to the arc of graph.
Definition graph-dry.H:2802
Node * get_src_node(Arc *arc) const noexcept
Return the source node of arc (only for directed graphs)
Definition graph-dry.H:731
constexpr size_t get_num_nodes() const noexcept
Return the total of nodes of graph.
Definition graph-dry.H:695
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
Node * get_tgt_node(Arc *arc) const noexcept
Return the target node of arc (only for directed graphs)
Definition graph-dry.H:737
Determines if a graph g is connected.
void demo_spanning_tree()
void demo_strongly_connected()
void demo_connected_components()
void print_graph(GT &g, const string &title)
GT::Node * find_or_create(GT &g, const string &name)
static void usage(const char *prog)
static bool has_flag(int argc, char *argv[], const char *flag)
void add_edge(GT &g, const string &src, const string &tgt, int weight=1)
void demo_network_analysis()
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
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
Graph connectivity and connected components.
Generic graph and digraph implementations.
Spanning tree generation algorithms.
Graph connectivity testing.