Graph Algorithms

Has Path (Graph Traversal)

Determines whether a path exists between two nodes in a directed graph. Includes both Depth-First Search (DFS) and Breadth-First Search (BFS) implementations.

The graph is represented as an adjacency list.

type Graph = Record<string, string[]>;
 
// Depth-First Search
const hasPath = (
  graph: Graph,
  src: string,
  dst: string,
): boolean => {
  if (src === dst) return true;
 
  for (const neighbor of graph[src]) {
    if (hasPath(graph, neighbor, dst)) {
      return true;
    }
  }
 
  return false;
};
 
// Breadth-First Search (uncomment to use)
/*
const hasPath = (
  graph: Graph,
  src: string,
  dst: string,
): boolean => {
  const queue: string[] = [src];
 
  while (queue.length) {
    const current = queue.shift();
    if (current === dst) return true;
 
    if (current && graph[current]) {
      for (const neighbor of graph[current]) {
        queue.push(neighbor);
      }
    }
  }
 
  return false;
};
*/
 
const adjacentList = {
  f: ["g", "i"],
  g: ["h"],
  h: [],
  i: ["g", "k"],
  j: ["i"],
  k: [],
};
 
console.log(hasPath(adjacentList, "f", "k")); // true
console.log(hasPath(adjacentList, "f", "j")); // false
 
console.log(
  hasPath(
    {
      v: ["x", "w"],
      w: [],
      x: [],
      y: ["z"],
      z: [],
    },
    "v",
    "z",
  ),
); // false

Undirected Path

Checks if a path exists between two nodes in an undirected graph, using DFS with a visited set to avoid cycles.

The graph is built from an edges list using an adjacency list structure.

const undirectedPath = (
  edges: [string, string][],
  nodeA: string,
  nodeB: string,
): boolean => {
  const graph = buildGraph(edges);
  return hasPath(graph, nodeA, nodeB, new Set());
};
 
const buildGraph = (edges: [string, string][]) => {
  const graph: Record<string, string[]> = {};
 
  for (const [a, b] of edges) {
    if (!(a in graph)) graph[a] = [];
    if (!(b in graph)) graph[b] = [];
    graph[a].push(b);
    graph[b].push(a);
  }
 
  return graph;
};
 
const hasPath = (
  graph: Record<string, string[]>,
  src: string,
  dst: string,
  visited: Set<string>,
): boolean => {
  if (src === dst) return true;
  if (visited.has(src)) return false;
  visited.add(src);
 
  for (const neighbor of graph[src]) {
    if (hasPath(graph, neighbor, dst, visited)) {
      return true;
    }
  }
 
  return false;
};
 
const edges: [string, string][] = [
  ["i", "j"],
  ["k", "i"],
  ["m", "k"],
  ["k", "l"],
  ["o", "n"],
];
 
console.log(undirectedPath(edges, "j", "m")); // true
console.log(undirectedPath(edges, "k", "o")); // false