Let's start with the observation that BFS searches for shortest paths from a given vertex in a source if the graph is unweighted. In other words, we consider the path length as the number of edges in the path.
Here is a simple way to build an unweighted graph:
function Graph() { var neighbors = this.neighbors = {}; // Key = vertex, value = array of neighbors. this.addEdge = function (u, v) { if (neighbors[u] === undefined) { // Add the edge u -> v. neighbors[u] = []; } neighbors[u].push(v); if (neighbors[v] === undefined) { // Also add the edge v -> u so as neighbors[v] = []; // to implement an undirected graph. } // For a directed graph, delete neighbors[v].push(u); // these four lines. }; return this; }
Please note that we have implemented an undirected graph. As indicated in the inline comments, you can change the code to build a directed graph by removing four lines from the addEdge function.
This BFS implementation will work equally well on a directed graph:
function bfs(graph, source) { var queue = [ { vertex: source, count: 0 } ], visited = { source: true }, tail = 0; while (tail < queue.length) { var u = queue[tail].vertex, count = queue[tail++].count; // Pop a vertex off the queue. print('distance from ' + source + ' to ' + u + ': ' + count); graph.neighbors[u].forEach(function (v) { if (!visited[v]) { visited[v] = true; queue.push({ vertex: v, count: count + 1 }); } }); } }
To find the shortest path between two given vertices and display the vertices along the path, we must remember the predecessor of each vertex when we examine the graph:
function shortestPath(graph, source, target) { if (source == target) { // Delete these four lines if print(source); // you want to look for a cycle return; // when the source is equal to } // the target. var queue = [ source ], visited = { source: true }, predecessor = {}, tail = 0; while (tail < queue.length) { var u = queue[tail++], // Pop a vertex off the queue. neighbors = graph.neighbors[u]; for (var i = 0; i < neighbors.length; ++i) { var v = neighbors[i]; if (visited[v]) { continue; } visited[v] = true; if (v === target) { // Check if the path is complete. var path = [ v ]; // If so, backtrack through the path. while (u !== source) { u = predecessor[u]; path.push(u); } path.reverse(); print(path.join(' → ')); return; } predecessor[v] = u; queue.push(v); } } print('there is no path from ' + source + ' to ' + target); }
The following snippet demonstrates these operations on the chart that you indicated in your question. First we find the shortest paths to all the vertices reachable from A Then we find the shortest path from B to G and from G to A
function Graph() { var neighbors = this.neighbors = {};
body { font-family: 'Source Code Pro', monospace; font-size: 12px; }
<link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Source+Code+Pro"> <div id="display"></id>