@@ -4,56 +4,57 @@ import depthFirstSearch from '../depth-first-search/depthFirstSearch';
44 * Detect cycle in undirected graph using Depth First Search.
55 *
66 * @param {Graph } graph
7+ * @returns {Vertex[] | null } ordered array of vertices forming the cycle (first === last), or null
78 */
89export default function detectUndirectedCycle ( graph ) {
9- let cycle = null ;
10+ let cycle = null ; // will hold ordered array once found
1011
11- // List of vertices that we have visited.
12- const visitedVertices = { } ;
12+ const visitedVertices = { } ; // visited vertices
13+ const parents = { } ; // parent for every visited vertex
1314
14- // List of parents vertices for every visited vertex.
15- const parents = { } ;
16-
17- // Callbacks for DFS traversing.
1815 const callbacks = {
1916 allowTraversal : ( { currentVertex, nextVertex } ) => {
20- // Don't allow further traversal in case if cycle has been detected.
21- if ( cycle ) {
22- return false ;
23- }
17+ if ( cycle ) return false ; // stop traversal once cycle is found
2418
25- // Don't allow traversal from child back to its parent.
2619 const currentVertexParent = parents [ currentVertex . getKey ( ) ] ;
27- const currentVertexParentKey = currentVertexParent ? currentVertexParent . getKey ( ) : null ;
20+ const currentVertexParentKey = currentVertexParent
21+ ? currentVertexParent . getKey ( )
22+ : null ;
2823
2924 return currentVertexParentKey !== nextVertex . getKey ( ) ;
3025 } ,
26+
3127 enterVertex : ( { currentVertex, previousVertex } ) => {
3228 if ( visitedVertices [ currentVertex . getKey ( ) ] ) {
33- // Compile cycle path based on parents of previous vertices.
34- cycle = { } ;
35-
36- let currentCycleVertex = currentVertex ;
37- let previousCycleVertex = previousVertex ;
38-
39- while ( previousCycleVertex . getKey ( ) !== currentVertex . getKey ( ) ) {
40- cycle [ currentCycleVertex . getKey ( ) ] = previousCycleVertex ;
41- currentCycleVertex = previousCycleVertex ;
42- previousCycleVertex = parents [ previousCycleVertex . getKey ( ) ] ;
29+ // Build ordered cycle array
30+ const startKey = currentVertex . getKey ( ) ;
31+ const cycleArr = [ currentVertex ] ;
32+
33+ let walker = previousVertex ;
34+ while ( walker && walker . getKey ( ) !== startKey ) {
35+ cycleArr . push ( walker ) ;
36+ walker = parents [ walker . getKey ( ) ] ;
4337 }
4438
45- cycle [ currentCycleVertex . getKey ( ) ] = previousCycleVertex ;
39+ cycleArr . push ( currentVertex ) ; // close the cycle
40+ cycle = cycleArr ;
4641 } else {
47- // Add next vertex to visited set.
4842 visitedVertices [ currentVertex . getKey ( ) ] = currentVertex ;
4943 parents [ currentVertex . getKey ( ) ] = previousVertex ;
5044 }
5145 } ,
5246 } ;
5347
54- // Start DFS traversing.
55- const startVertex = graph . getAllVertices ( ) [ 0 ] ;
56- depthFirstSearch ( graph , startVertex , callbacks ) ;
48+ const allVertices = graph . getAllVertices ( ) ;
49+ for ( let i = 0 ; i < allVertices . length ; i += 1 ) {
50+ const startVertex = allVertices [ i ] ;
51+
52+ if ( ! visitedVertices [ startVertex . getKey ( ) ] ) {
53+ depthFirstSearch ( graph , startVertex , callbacks ) ;
54+
55+ if ( cycle ) break ; // early exit once cycle is found
56+ }
57+ }
5758
5859 return cycle ;
5960}
0 commit comments