235using namespace Aleph;
251 for (
auto it = g.
get_node_it(); it.has_curr(); it.next())
252 if (it.get_curr()->get_info() == name)
253 return it.get_curr();
263 auto* node =
nit.get_curr();
264 cout <<
" " << node->get_info() <<
" → ";
268 auto* arc =
ait.get_curr();
270 if (!first)
cout <<
", ";
271 cout << tgt->get_info();
274 if (first)
cout <<
"(none)";
285 cout <<
"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
286 cout <<
"Example 1: Basic Strongly Connected Components\n";
287 cout <<
"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n";
333 cout <<
"\n▶ Running Kosaraju's Algorithm:\n\n";
340 cout <<
" Found " <<
sccs.
size() <<
" strongly connected components:\n\n";
347 for (
auto it =
scc.get_node_it(); it.has_curr(); it.next())
349 if (!first)
cout <<
", ";
357 cout <<
" Internal arcs: " <<
scc.get_num_arcs() <<
"\n\n";
365 cout <<
" " << src->get_info() <<
" → " << tgt->get_info() <<
"\n";
375 cout <<
"\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
376 cout <<
"Example 2: Lightweight SCC Detection (Node Lists Only)\n";
377 cout <<
"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n";
379 cout <<
"When you only need to know which nodes belong to which component,\n";
380 cout <<
"the lightweight version is more efficient (no subgraph construction).\n\n";
400 cout <<
"▶ Running lightweight Kosaraju:\n\n";
413 if (!first)
cout <<
", ";
414 cout << node->get_info();
427 cout <<
"\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
428 cout <<
"Example 3: Fully Strongly Connected Graph\n";
429 cout <<
"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n";
463 cout <<
"\n▶ Result:\n\n";
467 cout <<
" ✓ The graph is STRONGLY CONNECTED\n";
469 cout <<
" ✗ The graph is NOT strongly connected\n";
478 cout <<
"\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
479 cout <<
"Example 4: Directed Acyclic Graph (DAG)\n";
480 cout <<
"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n";
482 cout <<
"In a DAG, every SCC contains exactly one node (no cycles).\n\n";
509 cout <<
"\n▶ Result:\n\n";
514 cout <<
"\n ✓ This is a DAG (each node is its own SCC)\n";
523 cout <<
"\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
524 cout <<
"Example 5: Kosaraju vs Tarjan's Algorithm\n";
525 cout <<
"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n";
528┌────────────────────────────────────────────────────────────────────────┐
529│ SCC Algorithm Comparison │
530├────────────────────────────────────────────────────────────────────────┤
531│ Aspect │ Kosaraju │ Tarjan │
532├────────────────────┼────────────────────┼──────────────────────────────┤
533│ DFS passes │ 2 │ 1 │
534│ Extra space │ O(V+E) for G^T │ O(V) for stack │
535│ Time complexity │ O(V + E) │ O(V + E) │
536│ Implementation │ Simpler │ More complex │
537│ Order of SCCs │ Reverse topo order │ Any order │
538├────────────────────┴────────────────────┴──────────────────────────────┤
539│ When to use Kosaraju: │
540│ • Need SCCs in reverse topological order │
541│ • Simpler implementation preferred │
542│ • Memory not critical (need space for transposed graph) │
544│ When to use Tarjan: │
545│ • Memory is critical (no transposed graph needed) │
546│ • Only one DFS pass preferred │
547│ • Already have Tarjan's implementation for other purposes │
548└────────────────────────────────────────────────────────────────────────┘
570 cout <<
"\n Verification on sample graph:\n";
575 cout <<
" ✓ Both algorithms agree!\n";
584 cout <<
"\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
585 cout <<
"Example 6: Real-World Applications of SCCs\n";
586 cout <<
"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n";
589 1. CIRCULAR DEPENDENCY DETECTION
590 ─────────────────────────────
591 In build systems (Make, CMake) or package managers (npm, pip),
592 an SCC with more than one node indicates circular dependencies.
596 Boolean satisfiability with clauses of 2 literals can be solved
597 in O(V+E) using SCC decomposition of the implication graph.
599 3. SOCIAL NETWORK ANALYSIS
600 ───────────────────────
601 SCCs identify tightly-knit communities where information flows
602 freely in both directions between all members.
606 SCCs help identify clusters of web pages that link to each other,
607 useful in understanding website structure.
609 5. COMPILER OPTIMIZATION
610 ─────────────────────
611 SCCs in data flow graphs help identify loops and enable
612 optimizations like loop-invariant code motion.
614 6. DATABASE QUERY OPTIMIZATION
615 ──────────────────────────
616 Finding cycles in query dependency graphs helps detect
617 and handle recursive queries.
627 cout <<
"Usage: " <<
prog <<
" [--compare] [--help]\n";
628 cout <<
"\nIf no flags are given, all demos are executed.\n";
633 for (
int i = 1; i <
argc; ++i)
634 if (std::strcmp(
argv[i], flag) == 0)
649 cout <<
"╔══════════════════════════════════════════════════════════════════════╗\n";
650 cout <<
"║ Kosaraju's Algorithm for Strongly Connected Components ║\n";
651 cout <<
"╚══════════════════════════════════════════════════════════════════════╝\n\n";
Tarjan's algorithm for strongly connected components.
WeightedDigraph::Node Node
Generic directed graph (digraph) wrapper template.
typename BaseGraph::Arc Arc
typename BaseGraph::Node Node
Dynamic singly linked list with functional programming support.
size_t size() const noexcept
Count the number of elements of the list.
virtual Node * insert_node(Node *node) noexcept
Insertion of a node already allocated.
Arc * insert_arc(Node *src_node, Node *tgt_node, void *a)
Node * get_src_node(Arc *arc) const noexcept
Return the source node of arc (only for directed graphs)
Out_Iterator get_out_it(Node *p) const noexcept
Return an output iterator on the incoming nodes to p
constexpr size_t get_num_nodes() const noexcept
Return the total of nodes of graph.
constexpr size_t get_num_arcs() const noexcept
auto get_node_it() const noexcept
Obtains an iterator to the nodes of graph.
Node * get_tgt_node(Arc *arc) const noexcept
Return the target node of arc (only for directed graphs)
void kosaraju_connected_components(const GT &g, DynList< GT > &blk_list, DynList< typename GT::Arc * > &arc_list)
Compute strongly connected components using Kosaraju's algorithm.
#define NODE_COOKIE(p)
Return the node cookie
Kosaraju's algorithm for finding strongly connected components.
void print_graph(Graph &g)
void example_strongly_connected()
void example_applications()
void example_basic_sccs()
static void usage(const char *prog)
Node * find_node(Graph &g, const string &name)
void example_comparison_tarjan()
static bool has_flag(int argc, char *argv[], const char *flag)
void example_lightweight_version()
Main namespace for Aleph-w library functions.
DynList< T > maps(const C &c, Op op)
Classic map operation.
Arc of graph implemented with double-linked adjacency lists.
Generic graph and digraph implementations.