6
6
* Created by Mayur Kulkarni on 2/5/2017.
7
7
*/
8
8
public class Graph <T > {
9
+ /**
10
+ * Creates a generic Graph
11
+ *
12
+ * Attributes:
13
+ * size: represents size of the graph
14
+ * graph: HashMap with key as node and value as their adjacency list
15
+ * isUnidirectional: true if graph is unidirectional
16
+ * time: used for articulation point, starts from 0, increments after
17
+ * passing every vertex.
18
+ */
9
19
private int size ;
10
20
private Map <T , List <T >> graph ;
11
21
private boolean isUniDirectional ;
12
22
private int time = 0 ;
13
23
24
+ /**
25
+ * Constructor of graph
26
+ * @param size size of graph
27
+ * @param isUniDirectional whether or not it is bidirectional.
28
+ */
14
29
public Graph (int size , boolean isUniDirectional ) {
15
30
this .size = size ;
16
31
this .isUniDirectional = isUniDirectional ;
17
32
graph = new HashMap <>();
18
33
}
19
34
35
+ /**
36
+ * Run the program using custom graph!
37
+ * @param args
38
+ */
20
39
public static void main (String [] args ) {
21
40
Graph <Character > graph = new Graph <>(5 , false );
22
41
graph .addEdge ('A' , 'B' );
@@ -25,6 +44,10 @@ public static void main(String[] args) {
25
44
graph .printArticulationPoints ();
26
45
}
27
46
47
+ /**
48
+ * Pretty printing
49
+ * @return nice representation of graph
50
+ */
28
51
@ Override
29
52
public String toString () {
30
53
StringBuilder sb = new StringBuilder ();
@@ -35,26 +58,44 @@ public String toString() {
35
58
return sb .toString ();
36
59
}
37
60
38
- private void insToMapGraph (T from , T to ) {
39
- graph .compute (from , (key , value ) -> {
61
+ /**
62
+ * Inserts toNode to the adjacenct list of fromNode
63
+ *
64
+ * @param fromNode from node
65
+ * @param toNode to node
66
+ */
67
+ private void insToMapGraph (T fromNode , T toNode ) {
68
+ graph .compute (fromNode , (key , value ) -> {
40
69
if (value == null ) {
41
70
List <T > adjList = new ArrayList <>();
42
- adjList .add (to );
71
+ adjList .add (toNode );
43
72
return adjList ;
44
73
} else {
45
- value .add (to );
74
+ value .add (toNode );
46
75
return value ;
47
76
}
48
77
});
49
78
}
50
79
51
- public void addEdge (T from , T to ) {
52
- insToMapGraph (from , to );
80
+ /**
81
+ * Adds an edge in graph. If current graph is bidirectional,
82
+ * also adds edge from toNode to fromNode
83
+ *
84
+ * @param fromNode from node
85
+ * @param toNode to node
86
+ */
87
+ public void addEdge (T fromNode , T toNode ) {
88
+ insToMapGraph (fromNode , toNode );
53
89
if (!isUniDirectional ) {
54
- insToMapGraph (to , from );
90
+ insToMapGraph (toNode , fromNode );
55
91
}
56
92
}
57
93
94
+ /**
95
+ * Returns the adjacency list of the graph
96
+ * @param key the index of node you're interested in
97
+ * @return adjacency list of node specifief in key
98
+ */
58
99
public List <T > adjacencyList (T key ) {
59
100
if (graph .containsKey (key )) {
60
101
return graph .get (key );
@@ -63,6 +104,9 @@ public List<T> adjacencyList(T key) {
63
104
}
64
105
}
65
106
107
+ /**
108
+ * Prints the articulation points of current graph
109
+ */
66
110
public void printArticulationPoints () {
67
111
Set <T > visited = new HashSet <T >();
68
112
Map <T , Integer > visitedTime = new HashMap <T , Integer >();
@@ -75,6 +119,15 @@ public void printArticulationPoints() {
75
119
System .out .println (articulationPoints );
76
120
}
77
121
122
+ /**
123
+ * DFS the graph represented by graph HashMap and find out articulation points
124
+ * @param visited denotes the nodes which are already visited
125
+ * @param visitedTime denotes the order in which nodes are visited
126
+ * @param currNode the current node of this traversa;
127
+ * @param lowTime denotes the minimum lowTime of adjacent vertices
128
+ * @param parent parent of the current node
129
+ * @param articulationPoints articulation points of the current graph
130
+ */
78
131
public void DFS (Set <T > visited ,
79
132
Map <T , Integer > visitedTime ,
80
133
T currNode , Map <T , Integer > lowTime ,
@@ -86,7 +139,7 @@ public void DFS(Set<T> visited,
86
139
int childCount = 0 ;
87
140
boolean isArticulationPoint = false ;
88
141
for (T adjNode : this .adjacencyList (currNode )) {
89
-
142
+ // remember, we ignore the parents of current node
90
143
if (adjNode .equals (parent .get (currNode ))) continue ;
91
144
92
145
if (!visited .contains (adjNode )) {
@@ -102,13 +155,23 @@ public void DFS(Set<T> visited,
102
155
lowTime .compute (currNode , (node , lowtime ) -> Math .min (lowTime .get (currNode ), lowTime .get (adjNode )));
103
156
}
104
157
}
105
- if ((isParent (currNode , parent ) && childCount >= 2 )
106
- || (!isParent (currNode , parent ) && isArticulationPoint )) {
158
+ // first condition is satisfied only by root nodes of DFS, for rest of them there's
159
+ // the second one
160
+ if ((isRoot (currNode , parent ) && childCount >= 2 )
161
+ || (!isRoot (currNode , parent ) && isArticulationPoint )) {
107
162
articulationPoints .add (currNode );
108
163
}
109
164
}
110
165
111
- private boolean isParent (T currNode , Map <T , T > parent ) {
166
+ /**
167
+ * Tell whether the currNode is the root of the DFS or not.
168
+ * The root of the DFS will have null as it's parent
169
+ *
170
+ * @param currNode The node you're interested in
171
+ * @param parent parent HashMap who's key is node and value is it's parent
172
+ * @return
173
+ */
174
+ private boolean isRoot (T currNode , Map <T , T > parent ) {
112
175
return parent .get (currNode ) == null ;
113
176
}
114
177
}
0 commit comments