Skip to content

Commit f1252a6

Browse files
Merge pull request #84 from SUJALGOYALL/feature/prims-mst-visualizer
feat(graph): add Prim's Minimum Spanning Tree Visualizer with frontier and visited panels
2 parents d46cb94 + 6cd6b4e commit f1252a6

File tree

4 files changed

+457
-0
lines changed

4 files changed

+457
-0
lines changed

src/algorithms/graph/prim.js

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// src/algorithms/graph/prim.js
2+
3+
// Build adjacency list from list of edges
4+
function buildAdjacency(edges, n) {
5+
const adj = Array.from({ length: n }, () => []);
6+
for (const e of edges) {
7+
const u = e.from - 1;
8+
const v = e.to - 1;
9+
const w = e.weight;
10+
11+
adj[u].push({ u, v, w });
12+
adj[v].push({ u: v, v: u, w }); // undirected graph
13+
}
14+
return adj;
15+
}
16+
17+
/**
18+
* Prim's Algorithm – Step Generator
19+
* Yields one step at a time:
20+
* type: "consider" | "add" | "skip" | "done"
21+
* edge: {from, to, weight}
22+
* visited: boolean[]
23+
* frontier: edge[]
24+
* mst: collected MST edges
25+
*/
26+
export function* primSteps(edges, nodeCount, startNode = 1) {
27+
if (nodeCount === 0) {
28+
yield { type: "done", mst: [], visited: [], frontier: [] };
29+
return;
30+
}
31+
32+
const adj = buildAdjacency(edges, nodeCount);
33+
const visited = Array(nodeCount).fill(false);
34+
const mst = [];
35+
const frontier = [];
36+
37+
const pushEdges = (u) => {
38+
for (const { v, w } of adj[u]) {
39+
if (!visited[v]) {
40+
frontier.push({ from: u + 1, to: v + 1, weight: w });
41+
}
42+
}
43+
};
44+
45+
const startIdx = Math.max(1, Math.min(startNode, nodeCount)) - 1;
46+
visited[startIdx] = true;
47+
pushEdges(startIdx);
48+
49+
while (mst.length < nodeCount - 1 && frontier.length > 0) {
50+
frontier.sort((a, b) => a.weight - b.weight);
51+
const edge = frontier.shift();
52+
53+
yield {
54+
type: "consider",
55+
edge,
56+
visited: [...visited],
57+
frontier: [...frontier],
58+
mst: [...mst],
59+
};
60+
61+
const u = edge.from - 1;
62+
const v = edge.to - 1;
63+
64+
if (visited[u] && visited[v]) {
65+
yield {
66+
type: "skip",
67+
edge,
68+
visited: [...visited],
69+
frontier: [...frontier],
70+
mst: [...mst],
71+
};
72+
continue;
73+
}
74+
75+
const nextNode = visited[u] ? v : u;
76+
visited[nextNode] = true;
77+
78+
mst.push(edge);
79+
pushEdges(nextNode);
80+
81+
yield {
82+
type: "add",
83+
edge,
84+
visited: [...visited],
85+
frontier: [...frontier],
86+
mst: [...mst],
87+
};
88+
}
89+
90+
yield {
91+
type: "done",
92+
mst: [...mst],
93+
visited: [...visited],
94+
frontier: [...frontier],
95+
};
96+
}

0 commit comments

Comments
 (0)