queue для обхода и visited для защиты от повторов; путь восстанавливается через parent.Время – O(V + E), Память – O(V), где V (Vertices) – число вершин графа, E (Edges) – число рёбер графа
12// BFS: кратчайший путь в невзвешенном графе3function bfsPath(4 graph: Record<string, string[]>,5 start: string,6 isGoal: (name: string) => boolean7): string[] | null {8 const queue: string[] = [start];9 const visited = new Set<string>();10 const parent = new Map<string, string>();1112 while (queue.length) {13 const v = queue.shift()!;14 if (visited.has(v)) continue;15 visited.add(v);1617 if (isGoal(v)) {18 const path = [v];19 let cur = v;20 while (parent.has(cur)) {21 cur = parent.get(cur)!;22 path.unshift(cur);23 }24 return path;25 }2627 for (const n of graph[v] ?? []) {28 if (!visited.has(n)) {29 if (!parent.has(n)) parent.set(n, v);30 queue.push(n);31 }32 }33 }34 return null;35}3637const graph: Record<string, string[]> = {38 "you": [39 "alice",40 "bob",41 "claire"42 ],43 "alice": [44 "peggy"45 ],46 "bob": [47 "anuj",48 "peggy"49 ],50 "claire": [51 "thom",52 "jonny"53 ],54 "anuj": [],55 "peggy": [],56 "thom": [],57 "jonny": []58};5960const isSeller = (name: string) => name.endsWith('m');61const noSuch = (name: string) => name.startsWith('z');6263bfsPath(graph, 'you', isSeller) // -> ["you","claire","thom"]64bfsPath(graph, 'you', noSuch) // -> null65