Skip to content

Commit bd378dc

Browse files
committed
TopoSort Added
1 parent 241f127 commit bd378dc

File tree

9 files changed

+1335
-41
lines changed

9 files changed

+1335
-41
lines changed

package-lock.json

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
"@types/node": "^24.7.1",
3636
"@types/react": "^19.1.16",
3737
"@types/react-dom": "^19.1.9",
38-
"@vitejs/plugin-react": "^5.0.4",
38+
"@vitejs/plugin-react": "^5.1.0",
3939
"autoprefixer": "^10.4.21",
4040
"eslint": "^9.36.0",
4141
"eslint-plugin-react-hooks": "^5.2.0",
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
export default function runTopologicalSortDFS(nodes, edges) {
2+
const adjList = {};
3+
const visited = {};
4+
const topoOrder = [];
5+
const steps = [];
6+
let hasCycle = false;
7+
8+
// Initialize adjacency list
9+
nodes.forEach(node => {
10+
adjList[node] = [];
11+
visited[node] = 0; // 0 = unvisited, 1 = visiting, 2 = visited
12+
});
13+
14+
// Build graph
15+
edges.forEach(({ from, to }) => {
16+
adjList[from].push(to);
17+
});
18+
19+
function dfs(node) {
20+
if (hasCycle) return; // stop early if cycle found
21+
visited[node] = 1;
22+
steps.push({
23+
type: "visit",
24+
node,
25+
status: "visiting",
26+
message: `Visiting ${node}`
27+
});
28+
29+
for (const neighbor of adjList[node]) {
30+
if (visited[neighbor] === 0) {
31+
steps.push({
32+
type: "exploreEdge",
33+
from: node,
34+
to: neighbor,
35+
message: `Exploring edge ${node}${neighbor}`
36+
});
37+
dfs(neighbor);
38+
} else if (visited[neighbor] === 1) {
39+
// Back edge → cycle detected
40+
hasCycle = true;
41+
steps.push({
42+
type: "cycleDetected",
43+
from: node,
44+
to: neighbor,
45+
message: `Cycle detected via ${node}${neighbor}`
46+
});
47+
}
48+
}
49+
50+
visited[node] = 2;
51+
topoOrder.push(node);
52+
steps.push({
53+
type: "addToTopoOrder",
54+
node,
55+
topoOrder: [...topoOrder],
56+
message: `Added ${node} to topo order`
57+
});
58+
}
59+
60+
// Run DFS for all unvisited nodes
61+
for (const node of nodes) {
62+
if (visited[node] === 0) {
63+
steps.push({
64+
type: "startDFS",
65+
node,
66+
message: `Starting DFS from ${node}`
67+
});
68+
dfs(node);
69+
}
70+
}
71+
72+
if (!hasCycle) {
73+
topoOrder.reverse(); // reverse for correct topological order
74+
steps.push({
75+
type: "finalOrder",
76+
topoOrder: [...topoOrder],
77+
message: `Topological sort completed successfully`
78+
});
79+
} else {
80+
steps.push({
81+
type: "finalCycle",
82+
message: `Topological sort failed — cycle exists in graph`
83+
});
84+
}
85+
86+
return steps;
87+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
export default function runTopologicalSort(nodes, edges) {
2+
const inDegree = {};
3+
const adjList = {};
4+
5+
// Initialize in-degree and adjacency list
6+
nodes.forEach(node => {
7+
inDegree[node] = 0;
8+
adjList[node] = [];
9+
});
10+
11+
// Build graph
12+
edges.forEach(({ from, to }) => {
13+
adjList[from].push(to);
14+
inDegree[to]++;
15+
});
16+
17+
const steps = [];
18+
const queue = [];
19+
const topoOrder = [];
20+
21+
// Enqueue nodes with 0 in-degree
22+
for (const node of nodes) {
23+
if (inDegree[node] === 0) {
24+
queue.push(node);
25+
steps.push({
26+
type: "enqueue",
27+
node,
28+
reason: "in-degree 0"
29+
});
30+
}
31+
}
32+
33+
// Process nodes
34+
while (queue.length > 0) {
35+
const current = queue.shift();
36+
topoOrder.push(current);
37+
38+
steps.push({
39+
type: "visit",
40+
node: current,
41+
topoOrder: [...topoOrder]
42+
});
43+
44+
for (const neighbor of adjList[current]) {
45+
inDegree[neighbor]--;
46+
steps.push({
47+
type: "decrementInDegree",
48+
from: current,
49+
to: neighbor,
50+
newInDegree: inDegree[neighbor]
51+
});
52+
53+
if (inDegree[neighbor] === 0) {
54+
queue.push(neighbor);
55+
steps.push({
56+
type: "enqueue",
57+
node: neighbor,
58+
reason: "in-degree became 0"
59+
});
60+
}
61+
}
62+
}
63+
64+
// Check for cycles (if topoOrder doesn't include all nodes)
65+
if (topoOrder.length !== nodes.length) {
66+
steps.push({
67+
type: "cycleDetected",
68+
remainingNodes: nodes.filter(n => !topoOrder.includes(n))
69+
});
70+
}
71+
72+
return steps;
73+
}

0 commit comments

Comments
 (0)