Skip to content

Commit 702cc6b

Browse files
committed
Cycle issue fixed
1 parent e40a67b commit 702cc6b

File tree

1 file changed

+53
-20
lines changed

1 file changed

+53
-20
lines changed
Lines changed: 53 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,64 @@
11
import DisjointSet from '../../../data-structures/disjoint-set/DisjointSet';
22

33
/**
4-
* Detect cycle in undirected graph using disjoint sets.
5-
*
4+
* Detect and return the actual cycle path in an undirected graph using disjoint sets.
65
* @param {Graph} graph
6+
* @returns {Array|null} - Returns an array of vertex keys forming the cycle, or null if no cycle found.
77
*/
88
export default function detectUndirectedCycleUsingDisjointSet(graph) {
9-
// Create initial singleton disjoint sets for each graph vertex.
10-
/** @param {GraphVertex} graphVertex */
119
const keyExtractor = (graphVertex) => graphVertex.getKey();
1210
const disjointSet = new DisjointSet(keyExtractor);
13-
graph.getAllVertices().forEach((graphVertex) => disjointSet.makeSet(graphVertex));
14-
15-
// Go trough all graph edges one by one and check if edge vertices are from the
16-
// different sets. In this case joint those sets together. Do this until you find
17-
// an edge where to edge vertices are already in one set. This means that current
18-
// edge will create a cycle.
19-
let cycleFound = false;
20-
/** @param {GraphEdge} graphEdge */
21-
graph.getAllEdges().forEach((graphEdge) => {
22-
if (disjointSet.inSameSet(graphEdge.startVertex, graphEdge.endVertex)) {
23-
// Cycle found.
24-
cycleFound = true;
25-
} else {
26-
disjointSet.union(graphEdge.startVertex, graphEdge.endVertex);
27-
}
11+
const parentMap = new Map();
12+
13+
graph.getAllVertices().forEach((vertex) => {
14+
disjointSet.makeSet(vertex);
15+
parentMap.set(vertex.getKey(), null); // Initialize with no parent
2816
});
2917

30-
return cycleFound;
18+
for (const edge of graph.getAllEdges()) {
19+
const startKey = edge.startVertex.getKey();
20+
const endKey = edge.endVertex.getKey();
21+
22+
if (disjointSet.inSameSet(edge.startVertex, edge.endVertex)) {
23+
// Cycle detected: reconstruct cycle path
24+
return constructCyclePath(startKey, endKey, parentMap);
25+
}
26+
27+
// Save parent info (arbitrarily choosing one as child)
28+
parentMap.set(endKey, startKey);
29+
disjointSet.union(edge.startVertex, edge.endVertex);
30+
}
31+
32+
return null;
33+
}
34+
35+
/**
36+
* Construct an ordered cycle path using parent map.
37+
* @param {string} startKey
38+
* @param {string} endKey
39+
* @param {Map} parentMap
40+
* @returns {string[]} Ordered array of vertex keys forming a cycle
41+
*/
42+
function constructCyclePath(startKey, endKey, parentMap) {
43+
const pathToRoot = (key) => {
44+
const path = [];
45+
while (key !== null) {
46+
path.push(key);
47+
key = parentMap.get(key);
48+
}
49+
return path;
50+
};
51+
52+
const pathStart = pathToRoot(startKey);
53+
const pathEnd = pathToRoot(endKey);
54+
55+
// Find the last common ancestor
56+
const setStart = new Set(pathStart);
57+
const commonAncestor = pathEnd.find((key) => setStart.has(key));
58+
59+
// Slice paths up to the common ancestor
60+
const cycleStart = pathStart.slice(0, pathStart.indexOf(commonAncestor) + 1);
61+
const cycleEnd = pathEnd.slice(0, pathEnd.indexOf(commonAncestor)).reverse();
62+
63+
return [...cycleStart, ...cycleEnd, commonAncestor];
3164
}

0 commit comments

Comments
 (0)