diff --git a/package-lock.json b/package-lock.json
index 8fd0861..7343cb3 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -33,7 +33,7 @@
"@types/node": "^24.7.1",
"@types/react": "^19.1.16",
"@types/react-dom": "^19.1.9",
- "@vitejs/plugin-react": "^5.0.4",
+ "@vitejs/plugin-react": "^5.1.0",
"autoprefixer": "^10.4.21",
"eslint": "^9.36.0",
"eslint-plugin-react-hooks": "^5.2.0",
@@ -2424,6 +2424,7 @@
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.1.0.tgz",
"integrity": "sha512-4LuWrg7EKWgQaMJfnN+wcmbAW+VSsCmqGohftWjuct47bv8uE4n/nPpq4XjJPsxgq00GGG5J8dvBczp8uxScew==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@babel/core": "^7.28.4",
"@babel/plugin-transform-react-jsx-self": "^7.27.1",
diff --git a/package.json b/package.json
index 46755e2..8ae4e6b 100644
--- a/package.json
+++ b/package.json
@@ -35,7 +35,7 @@
"@types/node": "^24.7.1",
"@types/react": "^19.1.16",
"@types/react-dom": "^19.1.9",
- "@vitejs/plugin-react": "^5.0.4",
+ "@vitejs/plugin-react": "^5.1.0",
"autoprefixer": "^10.4.21",
"eslint": "^9.36.0",
"eslint-plugin-react-hooks": "^5.2.0",
diff --git a/src/algorithms/graph/topoSortDFS.js b/src/algorithms/graph/topoSortDFS.js
new file mode 100644
index 0000000..3d03ce3
--- /dev/null
+++ b/src/algorithms/graph/topoSortDFS.js
@@ -0,0 +1,87 @@
+export default function runTopologicalSortDFS(nodes, edges) {
+ const adjList = {};
+ const visited = {};
+ const topoOrder = [];
+ const steps = [];
+ let hasCycle = false;
+
+ // Initialize adjacency list
+ nodes.forEach(node => {
+ adjList[node] = [];
+ visited[node] = 0; // 0 = unvisited, 1 = visiting, 2 = visited
+ });
+
+ // Build graph
+ edges.forEach(({ from, to }) => {
+ adjList[from].push(to);
+ });
+
+ function dfs(node) {
+ if (hasCycle) return; // stop early if cycle found
+ visited[node] = 1;
+ steps.push({
+ type: "visit",
+ node,
+ status: "visiting",
+ message: `Visiting ${node}`
+ });
+
+ for (const neighbor of adjList[node]) {
+ if (visited[neighbor] === 0) {
+ steps.push({
+ type: "exploreEdge",
+ from: node,
+ to: neighbor,
+ message: `Exploring edge ${node} → ${neighbor}`
+ });
+ dfs(neighbor);
+ } else if (visited[neighbor] === 1) {
+ // Back edge → cycle detected
+ hasCycle = true;
+ steps.push({
+ type: "cycleDetected",
+ from: node,
+ to: neighbor,
+ message: `Cycle detected via ${node} → ${neighbor}`
+ });
+ }
+ }
+
+ visited[node] = 2;
+ topoOrder.push(node);
+ steps.push({
+ type: "addToTopoOrder",
+ node,
+ topoOrder: [...topoOrder],
+ message: `Added ${node} to topo order`
+ });
+ }
+
+ // Run DFS for all unvisited nodes
+ for (const node of nodes) {
+ if (visited[node] === 0) {
+ steps.push({
+ type: "startDFS",
+ node,
+ message: `Starting DFS from ${node}`
+ });
+ dfs(node);
+ }
+ }
+
+ if (!hasCycle) {
+ topoOrder.reverse(); // reverse for correct topological order
+ steps.push({
+ type: "finalOrder",
+ topoOrder: [...topoOrder],
+ message: `Topological sort completed successfully`
+ });
+ } else {
+ steps.push({
+ type: "finalCycle",
+ message: `Topological sort failed — cycle exists in graph`
+ });
+ }
+
+ return steps;
+}
diff --git a/src/algorithms/graph/topoSortKahn.js b/src/algorithms/graph/topoSortKahn.js
new file mode 100644
index 0000000..91de658
--- /dev/null
+++ b/src/algorithms/graph/topoSortKahn.js
@@ -0,0 +1,73 @@
+export default function runTopologicalSort(nodes, edges) {
+ const inDegree = {};
+ const adjList = {};
+
+ // Initialize in-degree and adjacency list
+ nodes.forEach(node => {
+ inDegree[node] = 0;
+ adjList[node] = [];
+ });
+
+ // Build graph
+ edges.forEach(({ from, to }) => {
+ adjList[from].push(to);
+ inDegree[to]++;
+ });
+
+ const steps = [];
+ const queue = [];
+ const topoOrder = [];
+
+ // Enqueue nodes with 0 in-degree
+ for (const node of nodes) {
+ if (inDegree[node] === 0) {
+ queue.push(node);
+ steps.push({
+ type: "enqueue",
+ node,
+ reason: "in-degree 0"
+ });
+ }
+ }
+
+ // Process nodes
+ while (queue.length > 0) {
+ const current = queue.shift();
+ topoOrder.push(current);
+
+ steps.push({
+ type: "visit",
+ node: current,
+ topoOrder: [...topoOrder]
+ });
+
+ for (const neighbor of adjList[current]) {
+ inDegree[neighbor]--;
+ steps.push({
+ type: "decrementInDegree",
+ from: current,
+ to: neighbor,
+ newInDegree: inDegree[neighbor]
+ });
+
+ if (inDegree[neighbor] === 0) {
+ queue.push(neighbor);
+ steps.push({
+ type: "enqueue",
+ node: neighbor,
+ reason: "in-degree became 0"
+ });
+ }
+ }
+ }
+
+ // Check for cycles (if topoOrder doesn't include all nodes)
+ if (topoOrder.length !== nodes.length) {
+ steps.push({
+ type: "cycleDetected",
+ remainingNodes: nodes.filter(n => !topoOrder.includes(n))
+ });
+ }
+
+ return steps;
+}
diff --git a/src/components/graph/TopoSortDFSVisualizer.jsx b/src/components/graph/TopoSortDFSVisualizer.jsx
new file mode 100644
index 0000000..7089612
--- /dev/null
+++ b/src/components/graph/TopoSortDFSVisualizer.jsx
@@ -0,0 +1,304 @@
+import React, { useState, useEffect, useMemo } from "react";
+
+export default function TopoSortGraphDFS({
+ nodes = [],
+ edges = [],
+ visited = [],
+ topoOrder = [],
+ highlight = {},
+}) {
+ const [positions, setPositions] = useState({});
+
+ // Arrange nodes in a circle
+ useEffect(() => {
+ if (nodes.length === 0) return;
+ const radius = 180;
+ const centerX = 300;
+ const centerY = 250;
+ const newPositions = {};
+ nodes.forEach((node, index) => {
+ const angle = (2 * Math.PI * index) / nodes.length;
+ newPositions[node] = {
+ x: centerX + radius * Math.cos(angle),
+ y: centerY + radius * Math.sin(angle),
+ };
+ });
+ setPositions(newPositions);
+ }, [nodes]);
+
+ // Dummy layout for idle mode
+ const dummyGraph = useMemo(() => {
+ const dummyNodes = Array.from({ length: 6 }).map((_, i) => {
+ const radius = 180;
+ const centerX = 300;
+ const centerY = 250;
+ const angle = (2 * Math.PI * i) / 6;
+ return {
+ id: i,
+ x: centerX + radius * Math.cos(angle),
+ y: centerY + radius * Math.sin(angle),
+ };
+ });
+
+ const dummyEdges = Array.from({ length: 8 }).map(() => {
+ const u = Math.floor(Math.random() * 6);
+ const v = (u + 1 + Math.floor(Math.random() * 5)) % 6;
+ return { u, v };
+ });
+
+ return { dummyNodes, dummyEdges };
+ }, []);
+
+ return (
+
+ {/* Graph Area */}
+
+
+
+
+ {/* Right Info Panel */}
+
+
+ 🧭 DFS-Based Topological Sort
+
+
+ {nodes.length === 0 ? (
+
+ Add nodes and edges to visualize DFS-based topological sorting.
+
+ ) : (
+ <>
+ {highlight && highlight.step && (
+
+ {highlight.step === "startDFS" && (
+
+ 🔍 Starting DFS from {highlight.node}
+
+ )}
+ {highlight.step === "visit" && (
+
+ 🌀 Visiting {highlight.node}
+
+ )}
+ {highlight.step === "exploreEdge" && (
+
+ ➡️ Exploring edge {highlight.from} → {highlight.to}
+
+ )}
+ {highlight.step === "cycleDetected" && (
+
+ ⚠️ Cycle detected between {highlight.from} → {highlight.to}
+
+ )}
+ {highlight.step === "addToTopoOrder" && (
+
+ ✅ Added {highlight.node} to topo order
+
+ )}
+ {highlight.step === "finalOrder" && (
+
+ 🏁 Topological Sort Completed
+
+ )}
+
+ )}
+
+
+
+
+ Visited:
+
+
+ {visited.length === 0 ? (
+ None yet
+ ) : (
+ visited.map((n) => (
+
+ {n}
+
+ ))
+ )}
+
+
+
+
+
+ Topological Order:
+
+
+ {topoOrder.length === 0 ? (
+ Empty
+ ) : (
+ topoOrder.map((n) => (
+
+ {n}
+
+ ))
+ )}
+
+
+
+ >
+ )}
+
+
+ );
+}
diff --git a/src/components/graph/TopoSortKahnVisualizer.jsx b/src/components/graph/TopoSortKahnVisualizer.jsx
new file mode 100644
index 0000000..5a827e2
--- /dev/null
+++ b/src/components/graph/TopoSortKahnVisualizer.jsx
@@ -0,0 +1,286 @@
+import React, { useState, useEffect, useMemo } from "react";
+
+export default function TopoSortGraph({
+ nodes = [],
+ edges = [],
+ processed = [],
+ queue = [],
+ highlight = {},
+}) {
+ const [positions, setPositions] = useState({});
+
+ // Arrange nodes in a circle
+ useEffect(() => {
+ if (nodes.length === 0) return;
+ const radius = 180;
+ const centerX = 300;
+ const centerY = 250;
+ const newPositions = {};
+ nodes.forEach((node, index) => {
+ const angle = (2 * Math.PI * index) / nodes.length;
+ newPositions[node] = {
+ x: centerX + radius * Math.cos(angle),
+ y: centerY + radius * Math.sin(angle),
+ };
+ });
+ setPositions(newPositions);
+ }, [nodes]);
+
+ // Dummy layout for idle mode
+ const dummyGraph = useMemo(() => {
+ const dummyNodes = Array.from({ length: 6 }).map((_, i) => {
+ const radius = 180;
+ const centerX = 300;
+ const centerY = 250;
+ const angle = (2 * Math.PI * i) / 6;
+ return {
+ id: i,
+ x: centerX + radius * Math.cos(angle),
+ y: centerY + radius * Math.sin(angle),
+ };
+ });
+
+ const dummyEdges = Array.from({ length: 8 }).map(() => {
+ const u = Math.floor(Math.random() * 6);
+ const v = (u + 1 + Math.floor(Math.random() * 5)) % 6;
+ return { u, v };
+ });
+
+ return { dummyNodes, dummyEdges };
+ }, []);
+
+ return (
+
+ {/* Graph Area */}
+
+
+
+
+ {/* Right Info Panel */}
+
+
+ 🧮 Kahn’s Algorithm — Topological Sort
+
+
+ {nodes.length === 0 ? (
+
+ Add nodes and edges to visualize topological sorting.
+
+ ) : (
+ <>
+ {highlight && highlight.step && (
+
+ {highlight.step === "enqueue" && (
+
+ ➕ Added {highlight.node} to queue (in-degree 0)
+
+ )}
+ {highlight.step === "process" && (
+
+ ⚙️ Processing {highlight.node}, removing outgoing edges
+
+ )}
+ {highlight.step === "done" && (
+
+ ✅ All nodes processed. Topological order found!
+
+ )}
+
+ )}
+
+
+
+
Queue:
+
+ {queue.length === 0 ? (
+ Empty
+ ) : (
+ queue.map((n) => (
+
+ {n}
+
+ ))
+ )}
+
+
+
+
+
Processed:
+
+ {processed.length === 0 ? (
+ None yet
+ ) : (
+ processed.map((n) => (
+
+ {n}
+
+ ))
+ )}
+
+
+
+ >
+ )}
+
+
+ );
+}
diff --git a/src/pages/graph/GraphPage.jsx b/src/pages/graph/GraphPage.jsx
index fbb98b1..f8a09a9 100644
--- a/src/pages/graph/GraphPage.jsx
+++ b/src/pages/graph/GraphPage.jsx
@@ -7,6 +7,8 @@ import FloydWarshall from "./FloydWarshall";
import CycleDetection from "./CycleDetection";
import DFSTraversal from "./DFSTraversal";
import BFS from "./BFS";
+import KahnTopologicalSort from "./TopoSortKahn";
+import DFSTopologicalSort from "./TopoSortDFS";
export default function GraphPage() {
const [selectedAlgo, setSelectedAlgo] = useState("");
@@ -14,47 +16,23 @@ export default function GraphPage() {
const renderAlgorithm = () => {
switch (selectedAlgo) {
case "bellman-ford":
- return (
-
-
-
- );
+ return ;
case "union-find":
- return (
-
-
-
- );
+ return ;
case "kruskal":
- return (
-
-
-
- );
+ return ;
case "floyd-warshall":
- return (
-
-
-
- );
- case "cycle-detection": // ✅ Added
- return (
-
-
-
- );
+ return ;
+ case "cycle-detection":
+ return ;
case "dfs-traversal":
- return (
-
-
-
- );
+ return ;
case "bfs":
- return (
-
-
-
- );
+ return ;
+ case "topo-kahn":
+ return ;
+ case "topo-dfs":
+ return ;
default:
return (
@@ -99,12 +77,15 @@ export default function GraphPage() {
+
-
-
+