-
Notifications
You must be signed in to change notification settings - Fork 31.1k
Expand file tree
/
Copy pathdetectUndirectedCycle.js
More file actions
60 lines (48 loc) · 1.84 KB
/
detectUndirectedCycle.js
File metadata and controls
60 lines (48 loc) · 1.84 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import depthFirstSearch from '../depth-first-search/depthFirstSearch';
/**
* Detect cycle in undirected graph using Depth First Search.
*
* @param {Graph} graph
* @returns {Vertex[] | null} ordered array of vertices forming the cycle (first === last), or null
*/
export default function detectUndirectedCycle(graph) {
let cycle = null; // will hold ordered array once found
const visitedVertices = {}; // visited vertices
const parents = {}; // parent for every visited vertex
const callbacks = {
allowTraversal: ({ currentVertex, nextVertex }) => {
if (cycle) return false; // stop traversal once cycle is found
const currentVertexParent = parents[currentVertex.getKey()];
const currentVertexParentKey = currentVertexParent
? currentVertexParent.getKey()
: null;
return currentVertexParentKey !== nextVertex.getKey();
},
enterVertex: ({ currentVertex, previousVertex }) => {
if (visitedVertices[currentVertex.getKey()]) {
// Build ordered cycle array
const startKey = currentVertex.getKey();
const cycleArr = [currentVertex];
let walker = previousVertex;
while (walker && walker.getKey() !== startKey) {
cycleArr.push(walker);
walker = parents[walker.getKey()];
}
cycleArr.push(currentVertex); // close the cycle
cycle = cycleArr;
} else {
visitedVertices[currentVertex.getKey()] = currentVertex;
parents[currentVertex.getKey()] = previousVertex;
}
},
};
const allVertices = graph.getAllVertices();
for (let i = 0; i < allVertices.length; i += 1) {
const startVertex = allVertices[i];
if (!visitedVertices[startVertex.getKey()]) {
depthFirstSearch(graph, startVertex, callbacks);
if (cycle) break; // early exit once cycle is found
}
}
return cycle;
}