class Graph {
adjacencyList: Map<string, string[]>;
constructor() {
this.adjacencyList = new Map();
}
addEdge(src: string, dest: string) {
if (!this.adjacencyList.has(src)) {
this.adjacencyList.set(src, []);
}
this.adjacencyList.get(src)!.push(dest);
}
hasCycle(): boolean {
const visiting = new Set<string>();
const visited = new Set<string>();
const dfs = (node: string): boolean => {
if (visiting.has(node)) return true; // cycle found
if (visited.has(node)) return false; // already checked
visiting.add(node); // mark node as visiting
for (const neighbor of this.adjacencyList.get(node) || []) {
if (dfs(neighbor)) return true; // cycle detected in recursion
}
visiting.delete(node); // done exploring node
visited.add(node); // mark node as visited
return false;
};
for (const node of this.adjacencyList.keys()) {
if (dfs(node)) return true; // cycle found
}
return false; // no cycle
}
}
// Driver code
const graph = new Graph();
graph.addEdge('A', 'B');
graph.addEdge('B', 'C');
graph.addEdge('C', 'A');
console.log(graph.hasCycle() ? 'Cycle found' : 'No cycle');if (visiting.has(node)) return true; // cycle found
Detect if current node is already in the visiting set, indicating a cycle
if (visited.has(node)) return false; // already checked
Skip nodes already fully explored to avoid repeated work
visiting.add(node); // mark node as visiting
Mark node as currently exploring to track recursion stack
for (const neighbor of this.adjacencyList.get(node) || []) { if (dfs(neighbor)) return true; }
Recursively visit all neighbors to detect cycles
visiting.delete(node); visited.add(node);
Mark node as fully explored after all neighbors checked
for (const node of this.adjacencyList.keys()) { if (dfs(node)) return true; }
Start DFS from each node to cover disconnected parts