@@ -7,11 +7,6 @@ class VisitMetadata {
7
7
constructor ( { discoveryTime, lowDiscoveryTime } ) {
8
8
this . discoveryTime = discoveryTime ;
9
9
this . lowDiscoveryTime = lowDiscoveryTime ;
10
-
11
- // We need this to know to which vertex we need to compare discovery time
12
- // when leaving the vertex.
13
- this . childVertex = null ;
14
-
15
10
// We need this in order to check graph root node, whether it has two
16
11
// disconnected children or not.
17
12
this . independantChildrenCount = 0 ;
@@ -28,10 +23,10 @@ export default function articulationPoints(graph) {
28
23
// Set of vertices we've already visited during DFS.
29
24
const visitedSet = { } ;
30
25
31
- // Set of articulation points found so far .
32
- const articulationPointsSet = [ ] ;
26
+ // Set of articulation points.
27
+ const articulationPointsSet = { } ;
33
28
34
- // Time needed to get to the current vertex.
29
+ // Time needed to discover to the current vertex.
35
30
let discoveryTime = 0 ;
36
31
37
32
// Peek the start vertex for DFS traversal.
@@ -53,9 +48,6 @@ export default function articulationPoints(graph) {
53
48
discoveryTime += 1 ;
54
49
55
50
if ( previousVertex ) {
56
- // Update child vertex information for previous vertex.
57
- visitedSet [ previousVertex . getKey ( ) ] . childVertex = currentVertex ;
58
-
59
51
// Update children counter for previous vertex.
60
52
visitedSet [ previousVertex . getKey ( ) ] . independantChildrenCount += 1 ;
61
53
}
@@ -64,44 +56,43 @@ export default function articulationPoints(graph) {
64
56
* @param {GraphVertex } currentVertex
65
57
* @param {GraphVertex } previousVertex
66
58
*/
67
- leaveVertex : ( { currentVertex } ) => {
68
- // Detect whether current vertex is articulation point or not.
69
- // To do so we need to check two (OR) conditions:
59
+ leaveVertex : ( { currentVertex, previousVertex } ) => {
60
+ if ( previousVertex === null ) {
61
+ // Don't do anything for the root vertex if it is already current (not previous one)
62
+ return ;
63
+ }
64
+
65
+ // Update the low time with the smallest time of adjacent vertices.
66
+ // Get minimum low discovery time from all neighbors.
67
+ /** @param {GraphVertex } neighbor */
68
+ visitedSet [ currentVertex . getKey ( ) ] . lowDiscoveryTime = currentVertex . getNeighbors ( ) . reduce (
69
+ ( lowestDiscoveryTime , neighbor ) => {
70
+ const neighborLowTime = visitedSet [ neighbor . getKey ( ) ] . lowDiscoveryTime ;
71
+ return neighborLowTime < lowestDiscoveryTime ? neighborLowTime : lowestDiscoveryTime ;
72
+ } ,
73
+ visitedSet [ currentVertex . getKey ( ) ] . lowDiscoveryTime ,
74
+ ) ;
75
+
76
+ // Detect whether previous vertex is articulation point or not.
77
+ // To do so we need to check two [OR] conditions:
70
78
// 1. Is it a root vertex with at least two independent children.
71
79
// 2. If its visited time is <= low time of adjacent vertex.
72
- if ( currentVertex === startVertex ) {
73
- // Check that it has at least two independent children.
74
- if ( visitedSet [ currentVertex . getKey ( ) ] . independantChildrenCount >= 2 ) {
75
- articulationPointsSet . push ( currentVertex ) ;
80
+ if ( previousVertex === startVertex ) {
81
+ // Check that root vertex has at least two independent children.
82
+ if ( visitedSet [ previousVertex . getKey ( ) ] . independantChildrenCount >= 2 ) {
83
+ articulationPointsSet [ previousVertex . getKey ( ) ] = previousVertex ;
76
84
}
77
85
} else {
78
- // Get child vertex low discovery time.
79
- let childVertexLowDiscoveryTime = null ;
80
- if ( visitedSet [ currentVertex . getKey ( ) ] . childVertex ) {
81
- const childVertexKey = visitedSet [ currentVertex . getKey ( ) ] . childVertex . getKey ( ) ;
82
- childVertexLowDiscoveryTime = visitedSet [ childVertexKey ] . lowDiscoveryTime ;
86
+ // Get current vertex low discovery time.
87
+ const currentLowDiscoveryTime = visitedSet [ currentVertex . getKey ( ) ] . lowDiscoveryTime ;
88
+
89
+ // Compare current vertex low discovery time with parent discovery time. Check if there
90
+ // are any short path (back edge) exists. If we can't get to current vertex other then
91
+ // via parent then the parent vertex is articulation point for current one.
92
+ const parentDiscoveryTime = visitedSet [ previousVertex . getKey ( ) ] . discoveryTime ;
93
+ if ( parentDiscoveryTime <= currentLowDiscoveryTime ) {
94
+ articulationPointsSet [ previousVertex . getKey ( ) ] = previousVertex ;
83
95
}
84
-
85
- // Compare child vertex low discovery time with current discovery time to if there
86
- // are any short path (back edge) exists. If we can get to child vertex faster then
87
- // to current one it means that there is a back edge exists (short path) and current
88
- // vertex isn't articulation point.
89
- const currentDiscoveryTime = visitedSet [ currentVertex . getKey ( ) ] . discoveryTime ;
90
- if ( currentDiscoveryTime <= childVertexLowDiscoveryTime ) {
91
- articulationPointsSet . push ( currentVertex ) ;
92
- }
93
-
94
- // Update the low time with the smallest time of adjacent vertices.
95
-
96
- // Get minimum low discovery time from all neighbors.
97
- /** @param {GraphVertex } neighbor */
98
- visitedSet [ currentVertex . getKey ( ) ] . lowDiscoveryTime = currentVertex . getNeighbors ( ) . reduce (
99
- ( lowestDiscoveryTime , neighbor ) => {
100
- const neighborLowTime = visitedSet [ neighbor . getKey ( ) ] . lowDiscoveryTime ;
101
- return neighborLowTime < lowestDiscoveryTime ? neighborLowTime : lowestDiscoveryTime ;
102
- } ,
103
- visitedSet [ currentVertex . getKey ( ) ] . lowDiscoveryTime ,
104
- ) ;
105
96
}
106
97
} ,
107
98
allowTraversal : ( { nextVertex } ) => {
@@ -112,5 +103,5 @@ export default function articulationPoints(graph) {
112
103
// Do Depth First Search traversal over submitted graph.
113
104
depthFirstSearch ( graph , startVertex , dfsCallbacks ) ;
114
105
115
- return articulationPointsSet ;
106
+ return Object . values ( articulationPointsSet ) ;
116
107
}
0 commit comments