import { Graph, VertexType, EdgeType, Path, Vertex, PathType } from "./graph.ts" import { Queue, Stack } from "../iterables.ts" /** * Describes a search function for DFS and BFS. */ export type SearchFn = (v: VertexType, e: EdgeType | null, pathmap: Map>) => boolean | void /** * A graph solver, which can perform various algorithms on a graph. */ export class GraphSolver { G: Graph constructor(G: Graph) { this.G = G } /** * Performs a breadth-first search on a graph. Returns the path from the root to the found node. * @author MindfulMinun * @since 2022-10-23 */ BFS(root: Vertex, search: SearchFn): Path | null { const queue = new Queue([root]) const backPaths = new Map, Path>() const discovered = new WeakSet() discovered.add(root) backPaths.set(root, this.G.createPath(root)) for (const v of queue) { const found = search(v, backPaths.get(v)?.edges.at(-1) ?? null, backPaths) if (found) return backPaths.get(v) ?? null for (const E of v.adjacentEdges) { if (E.directed && v !== E.u) continue const w = E.not(v) if (!discovered.has(w)) { discovered.add(w) const path = backPaths.get(v)!.copy() path.addEdge(E) backPaths.set(w, path) queue.enqueue(w) } } } // If we iterate through all vertices without finding one that fulfills `search`, // then the found vertex is null and we should return null return null } /** * Performs a depth-first search on a graph. Returns the path from the root to the found node. * @author MindfulMinun * @since 2022-09-28 */ DFS(root: Vertex, search: SearchFn): Path | null { const stack = new Stack([root]) const backPaths = new Map, Path>() backPaths.set(root, this.G.createPath(root)) for (const v of stack) { const found = search(v, backPaths.get(v)?.edges.at(-1) ?? null, backPaths) if (found) return backPaths.get(v) ?? null for (const E of v.adjacentEdges) { if (E.directed && v !== E.u) continue const w = E.not(v) stack.push(w) // Update the path! const path = backPaths.get(v)!.copy() path.addEdge(E) backPaths.set(w, path) } } return null } }