Skip to content

Commit 5314191

Browse files
Merge branch 'main' into main
2 parents 459bd3c + d3d3ffa commit 5314191

File tree

18 files changed

+1950
-20
lines changed

18 files changed

+1950
-20
lines changed

README.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,6 @@ Visualize how algorithms explore and find paths across a grid.
5252
- Depth First Search (DFS)
5353
- Dijkstra’s Algorithm
5454
- A* Search
55-
- Greedy Best-First Search
56-
- Bellman-Ford
5755

5856
**Interactive Options:**
5957
- Set start and end points

public/graph.png

4.99 KB
Loading

src/App.jsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
import React from "react";
22
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
3-
import Homepage from "./pages/Homepage";
3+
// import UnionFindPage from "../src/pages/graph/UnionFind.jsx"; // ✅ Import Union-Find Page
44
import SortingPage from "./pages/sorting/SortingPage";
5+
import GraphPage from "./pages/graph/GraphPage";
6+
import Homepage from "./pages/Homepage.jsx";
57

68
function App() {
79
return (
810
<Router>
911
<Routes>
1012
<Route path="/" element={<Homepage />} />
13+
{/* <Route path="/graph/union-find" element={<UnionFindPage />} /> */}
1114
<Route path="/sorting" element={<SortingPage />} />
15+
<Route path="/graph" element={<GraphPage />} />
1216
</Routes>
1317
</Router>
1418
);
1519
}
1620

17-
export default App;
21+
export default App;
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
export default function runBellmanFord(nodes, edges, source) {
2+
const dist = {};
3+
nodes.forEach(n => dist[n] = Infinity);
4+
dist[source] = 0;
5+
6+
const steps = [];
7+
8+
// Relax edges |V|-1 times
9+
for (let i = 0; i < nodes.length - 1; i++) {
10+
for (const edge of edges) {
11+
const { from, to, weight } = edge;
12+
const step = {
13+
type: "relax",
14+
iteration: i + 1,
15+
edge,
16+
prevDistance: dist[to]
17+
};
18+
19+
if (dist[from] + weight < dist[to]) {
20+
dist[to] = dist[from] + weight;
21+
step.updatedDistance = dist[to];
22+
}
23+
24+
steps.push(step);
25+
}
26+
}
27+
28+
// Check for negative weight cycles
29+
for (const edge of edges) {
30+
const { from, to, weight } = edge;
31+
if (dist[from] + weight < dist[to]) {
32+
steps.push({ type: "negativeCycle", edge });
33+
}
34+
}
35+
36+
return steps;
37+
}

src/algorithms/graph/kruskal.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// src/algorithms/graph/kruskal.js
2+
3+
class DSU {
4+
constructor(n) {
5+
this.parent = Array.from({ length: n }, (_, i) => i);
6+
this.rank = Array(n).fill(0);
7+
}
8+
9+
find(x) {
10+
if (this.parent[x] !== x) {
11+
this.parent[x] = this.find(this.parent[x]);
12+
}
13+
return this.parent[x];
14+
}
15+
16+
union(x, y) {
17+
const rx = this.find(x);
18+
const ry = this.find(y);
19+
if (rx === ry) return false;
20+
21+
if (this.rank[rx] < this.rank[ry]) this.parent[rx] = ry;
22+
else if (this.rank[rx] > this.rank[ry]) this.parent[ry] = rx;
23+
else {
24+
this.parent[ry] = rx;
25+
this.rank[rx]++;
26+
}
27+
return true;
28+
}
29+
30+
getState() {
31+
return [...this.parent];
32+
}
33+
}
34+
35+
// 🧠 Generator that yields every visualization step
36+
export function* kruskalSteps(edges, nodeCount) {
37+
const sortedEdges = [...edges].sort((a, b) => a.weight - b.weight);
38+
const dsu = new DSU(nodeCount);
39+
const mst = [];
40+
41+
for (let edge of sortedEdges) {
42+
yield { type: "consider", edge, dsu: dsu.getState() };
43+
44+
const merged = dsu.union(edge.from - 1, edge.to - 1);
45+
if (merged) {
46+
mst.push(edge);
47+
yield { type: "add", edge, mst: [...mst], dsu: dsu.getState() };
48+
} else {
49+
yield { type: "skip", edge, dsu: dsu.getState() };
50+
}
51+
}
52+
53+
yield { type: "done", mst, dsu: dsu.getState() };
54+
}

src/algorithms/graph/unionFind.js

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// src/algorithms/graph/unionFind.js
2+
3+
class UnionFind {
4+
constructor(n) {
5+
this.parent = Array.from({ length: n }, (_, i) => i);
6+
this.rank = Array(n).fill(0);
7+
this.steps = []; // For visualization steps
8+
}
9+
10+
find(x) {
11+
this.steps.push({ type: "find-start", node: x });
12+
if (this.parent[x] !== x) {
13+
const root = this.find(this.parent[x]);
14+
this.steps.push({
15+
type: "path-compression",
16+
node: x,
17+
newParent: root,
18+
});
19+
this.parent[x] = root;
20+
}
21+
this.steps.push({ type: "find-end", node: x, root: this.parent[x] });
22+
return this.parent[x];
23+
}
24+
25+
union(x, y) {
26+
const rootX = this.find(x);
27+
const rootY = this.find(y);
28+
29+
this.steps.push({
30+
type: "union-start",
31+
x,
32+
y,
33+
rootX,
34+
rootY,
35+
});
36+
37+
if (rootX === rootY) {
38+
this.steps.push({ type: "same-set", x, y });
39+
return;
40+
}
41+
42+
if (this.rank[rootX] < this.rank[rootY]) {
43+
this.parent[rootX] = rootY;
44+
this.steps.push({
45+
type: "union",
46+
parent: rootY,
47+
child: rootX,
48+
});
49+
} else if (this.rank[rootX] > this.rank[rootY]) {
50+
this.parent[rootY] = rootX;
51+
this.steps.push({
52+
type: "union",
53+
parent: rootX,
54+
child: rootY,
55+
});
56+
} else {
57+
this.parent[rootY] = rootX;
58+
this.rank[rootX]++;
59+
this.steps.push({
60+
type: "union-rank",
61+
parent: rootX,
62+
child: rootY,
63+
});
64+
}
65+
}
66+
67+
getSteps() {
68+
return this.steps;
69+
}
70+
}
71+
72+
export default UnionFind;
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// src/algorithms/sorting/mergeSort.js
2+
export function* mergeSort(array) {
3+
const arr = [...array];
4+
const n = arr.length;
5+
6+
if (n === 0) {
7+
yield { type: "done", array: arr };
8+
return;
9+
}
10+
11+
function* merge(l, m, r) {
12+
const left = arr.slice(l, m + 1);
13+
const right = arr.slice(m + 1, r + 1);
14+
let i = 0;
15+
let j = 0;
16+
let k = l;
17+
18+
while (i < left.length && j < right.length) {
19+
// highlight the two elements being compared (use their original indices)
20+
yield { type: "compare", indices: [l + i, m + 1 + j] };
21+
22+
if (left[i] <= right[j]) {
23+
arr[k] = left[i];
24+
yield { type: "swap", indices: [k, l + i], array: [...arr] };
25+
i++;
26+
} else {
27+
arr[k] = right[j];
28+
yield { type: "swap", indices: [k, m + 1 + j], array: [...arr] };
29+
j++;
30+
}
31+
k++;
32+
}
33+
34+
while (i < left.length) {
35+
arr[k] = left[i];
36+
yield { type: "swap", indices: [k, l + i], array: [...arr] };
37+
i++;
38+
k++;
39+
}
40+
41+
while (j < right.length) {
42+
arr[k] = right[j];
43+
yield { type: "swap", indices: [k, m + 1 + j], array: [...arr] };
44+
j++;
45+
k++;
46+
}
47+
48+
// mark merged positions as "min" to indicate they're in final place for this merge
49+
for (let idx = l; idx <= r; idx++) {
50+
yield { type: "min", index: idx };
51+
}
52+
}
53+
54+
function* mergeSortRec(l, r) {
55+
if (l >= r) return;
56+
const m = Math.floor((l + r) / 2);
57+
yield* mergeSortRec(l, m);
58+
yield* mergeSortRec(m + 1, r);
59+
yield* merge(l, m, r);
60+
}
61+
62+
yield* mergeSortRec(0, n - 1);
63+
yield { type: "done", array: arr };
64+
}

0 commit comments

Comments
 (0)