Skip to content

Commit 241f127

Browse files
Merge pull request #52 from 1ssatyamsingh/feature/bfs
added bfs traversal
2 parents 96ca629 + 052dbe2 commit 241f127

File tree

4 files changed

+440
-2
lines changed

4 files changed

+440
-2
lines changed

src/algorithms/graph/bfs.js

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/**
2+
* Builds an adjacency list from the edge array.
3+
* @param {Array} nodes - Array of node objects.
4+
* @param {Array} edges - Array of edge objects.
5+
* @returns {Map<number, number[]>} - An adjacency list.
6+
*/
7+
function buildAdjList(nodes, edges) {
8+
const adj = new Map();
9+
nodes.forEach((n) => adj.set(n.id, []));
10+
edges.forEach((edge) => {
11+
// This assumes a directed graph
12+
if (adj.has(edge.from)) {
13+
adj.get(edge.from).push(edge.to);
14+
}
15+
});
16+
return adj;
17+
}
18+
19+
/**
20+
* Generates all steps for a Breadth-First Search traversal.
21+
* @param {Array} nodes - Array of node objects.
22+
* @param {Array} edges - Array of edge objects.
23+
* @param {number} startNodeId - The ID of the node to start from.
24+
* @returns {Array} - An array of step objects for the visualization.
25+
*/
26+
export function bfsSteps(nodes, edges, startNodeId) {
27+
const adj = buildAdjList(nodes, edges);
28+
const steps = [];
29+
const queue = [];
30+
31+
// 'visited' tracks all nodes that have been *at least enqueued*.
32+
// This prevents adding the same node to the queue multiple times.
33+
const visited = new Set();
34+
35+
// 'discoveryOrder' tracks nodes *after* they are processed (dequeued).
36+
// This will control the "green" (visited) state in the UI.
37+
const discoveryOrder = [];
38+
39+
// --- Initial Step ---
40+
queue.push(startNodeId);
41+
visited.add(startNodeId); // Mark as visited *when enqueuing*
42+
43+
steps.push({
44+
type: "enqueue",
45+
node: startNodeId,
46+
log: `Starting BFS. Enqueueing Start Node ${startNodeId}.`,
47+
queueState: [...queue],
48+
visitedSet: new Set(), // Nothing is fully processed yet
49+
order: [],
50+
});
51+
52+
// --- Traversal Loop ---
53+
while (queue.length > 0) {
54+
const currentNodeId = queue.shift(); // FIFO: Dequeue from the front
55+
discoveryOrder.push(currentNodeId);
56+
57+
// --- Dequeue Step ---
58+
steps.push({
59+
type: "dequeue",
60+
node: currentNodeId,
61+
log: `Dequeuing Node ${currentNodeId} to process.`,
62+
queueState: [...queue],
63+
visitedSet: new Set(discoveryOrder), // Add to processed set
64+
order: [...discoveryOrder],
65+
});
66+
67+
const neighbors = adj.get(currentNodeId) || [];
68+
69+
for (const neighborId of neighbors) {
70+
if (!visited.has(neighborId)) {
71+
// --- Enqueue Neighbor Step ---
72+
visited.add(neighborId);
73+
queue.push(neighborId);
74+
75+
steps.push({
76+
type: "enqueue",
77+
node: neighborId,
78+
log: `Found unvisited neighbor ${neighborId}. Enqueueing.`,
79+
queueState: [...queue],
80+
visitedSet: new Set(discoveryOrder), // Processed set is unchanged
81+
order: [...discoveryOrder],
82+
});
83+
} else {
84+
// --- Skip Neighbor Step ---
85+
steps.push({
86+
type: "skip",
87+
node: neighborId,
88+
log: `Neighbor ${neighborId} already in queue or processed. Skipping.`,
89+
queueState: [...queue],
90+
visitedSet: new Set(discoveryOrder),
91+
order: [...discoveryOrder],
92+
});
93+
}
94+
}
95+
}
96+
97+
// --- Final Step ---
98+
steps.push({
99+
type: "done",
100+
node: null,
101+
log: "BFS complete. Queue is empty.",
102+
queueState: [],
103+
visitedSet: new Set(discoveryOrder),
104+
order: [...discoveryOrder],
105+
});
106+
107+
return steps;
108+
}

0 commit comments

Comments
 (0)