1
-
1
+ /**
2
+ * Long Project 5: Implementation of Minimum Spanning Tree using Prim1, Prim2, Prim3 and Kruskal's algorithm
3
+ * @author Axat Chaudhari (akc170000)
4
+ * @author Jaiminee Kataria (jxk172330)
5
+ * @author Param Parikh (psp170230)
6
+ * @author Tej Patel (txp172630)
7
+ */
2
8
package akc170000 ;
3
9
4
10
import rbk .Graph ;
15
21
import java .io .FileNotFoundException ;
16
22
import java .io .File ;
17
23
24
+ /**
25
+ * Class to computer MST on graph G.
26
+ * After running MST algorithm, MST is stored in list 'mst' corresponding predecessors are stored in 'parent'
27
+ * Weight is MST is stored in 'wmst'
28
+ */
18
29
public class MST extends GraphAlgorithm <MST .MSTVertex > {
19
- String algorithm ;
20
- public long wmst ;
21
- List <Edge > mst ;
30
+ String algorithm ; // which algorithm used to get MST
31
+ public long wmst ; // total weight of MST
32
+ List <Edge > mst ; // list containing edges in MST
22
33
23
34
MST (Graph g ) {
24
35
super (g , new MSTVertex ((Vertex ) null ));
25
36
}
26
37
38
+ /**
39
+ * MSTVertex to store additional properties for vertices of G for computing MST
40
+ */
27
41
public static class MSTVertex implements Index , Comparable <MSTVertex >, Factory {
28
- boolean seen ; // vertex is visited or not?
29
- Vertex parent ; // parent of vertex in MST
30
- int index ; // index of vertex in priority queue
31
- int d ; // weight of the smallest edge that connects v to some u in G
32
- Vertex vertex ; // corresponding vertex
33
- int rank ; // rank of node in UNION/FIND data structure
42
+ boolean seen ; // when v.seen = true: edge e (u,v), where v.d = w(e) is added in MST
43
+ Vertex parent ; // predecessor vertex in MST. When edge e (u, v) is added to MST, v.parent = u and v.d = w(e)
44
+ int index ; // index of vertex stored in priority queue
45
+ int d ; // weight of edge (u,v) that belongs to MST. v.d = w(e)
46
+ Vertex vertex ; // corresponding graph vertex
47
+ int rank ; // rank of vertex in UNION/FIND
34
48
MSTVertex root ; // root of vertex in UNION/FIND
35
49
MSTVertex (Vertex u ) {
36
50
seen = false ;
37
51
parent = null ;
38
52
d = Integer .MAX_VALUE ;
39
53
vertex = u ;
40
- root = this ;
54
+ root = this ; // vertex itself is its root node in the beginning
41
55
rank = 0 ;
42
56
}
43
57
44
58
MSTVertex (MSTVertex u ) { // for prim2
45
59
vertex = u .vertex ;
46
60
}
47
61
62
+ /**
63
+ * duplicate the MSTVeretx u
64
+ * @param u vertex to be copied
65
+ * @return new duplicated vertex
66
+ */
48
67
public MSTVertex make (Vertex u ) { return new MSTVertex (u ); }
49
68
69
+ /**
70
+ * set the position of vertex in IndexedPriorityQueue
71
+ * @param index index of vertex in IndexedPriorityQueue
72
+ */
50
73
public void putIndex (int index ) { this .index = index ; }
51
74
75
+ /**
76
+ * get the index where vertex is stored in IndexedPriorityQueue
77
+ * @return index of vertex
78
+ */
52
79
public int getIndex () { return index ; }
53
80
81
+ /**
82
+ * used in priority queue to compare weight of two edges e(u,v), e'(u', v') where v.d = w(e) and v'.d = w(e')
83
+ * @param other edge e'
84
+ * @return 1 if w(e) > w(e'), 0 if w(e) = w(e'), -1 if w(e) < w(e')
85
+ */
54
86
public int compareTo (MSTVertex other ) {
55
87
if (other == null || this .d > other .d ) return 1 ;
56
88
else if (this .d < other .d ) return -1 ;
57
89
else return 0 ;
58
90
}
59
91
92
+ /**
93
+ * find the root of vertex. point current vertex to root for immediate access in future
94
+ * @return root of vertex
95
+ */
60
96
public MSTVertex find (){
97
+ // recursive call while vertex's root is itself
61
98
if (!vertex .equals (root .vertex )){
62
- root = root .find ();
99
+ root = root .find (); // set direct pointer to its root
63
100
}
64
101
return root ;
65
102
}
66
103
104
+ /**
105
+ * union vertex 'rv' with current vertex
106
+ * @param rv vertex to union current vertex with
107
+ */
67
108
public void union (MSTVertex rv ){
109
+ // set root of smaller tree as a child of root with bigger tree.
110
+ // use rank to determine which tree is bigger
68
111
if (rank > rv .rank ){
69
112
rv .root = this ;
70
113
}else if (rank < rv .rank ){
71
114
root = rv ;
72
- }else {
115
+ }else { // if both tree has same rank, any one of two root vertices can become new root
73
116
rank ++;
74
117
rv .root = this ;
75
118
}
76
119
}
77
120
}
78
121
122
+ /**
123
+ * Kruskal's algorithm:
124
+ * - Sort edges is ascending order of weights
125
+ * - Add every edge in MST until all vertices in G are covered
126
+ * @return total weight of MST
127
+ */
79
128
public long kruskal () {
129
+ // initialization done in constructor
80
130
algorithm = "Kruskal" ;
81
131
Edge [] edgeArray = g .getEdgeArray ();
82
132
mst = new LinkedList <>();
83
133
wmst = 0 ;
84
134
Arrays .sort (edgeArray );
85
- for (Edge e : edgeArray ){
86
- MSTVertex ru = get (e .fromVertex ()).find ();
87
- MSTVertex rv = get (e .toVertex ()).find ();
88
- if (!ru .vertex .equals (rv .vertex )){
89
- mst .add (e );
90
- ru .union (rv );
135
+ for (Edge e : edgeArray ){ // for each edge e (u,v) in G
136
+ MSTVertex ru = get (e .fromVertex ()).find (); // root of u
137
+ MSTVertex rv = get (e .toVertex ()).find (); // root of v
138
+ if (!ru .vertex .equals (rv .vertex )){ // if both are not in same component
139
+ mst .add (e ); // add e to mst
140
+ ru .union (rv ); // combine two components
91
141
wmst += e .getWeight ();
92
142
}
93
143
}
144
+ // at the end #components in UNION/FIND = 1
94
145
return wmst ;
95
146
}
96
147
148
+ /**
149
+ * Prim3 (modification of Prim2)
150
+ * using Indexed queue so there are no duplicate vertices in priority queue
151
+ * @param s source vertex
152
+ * @return total weight of MST
153
+ */
97
154
public long prim3 (Vertex s ) {
98
155
algorithm = "indexed heaps" ;
156
+ //initialization
99
157
initialize ();
100
158
get (s ).d = 0 ;
101
159
mst = new LinkedList <>();
102
160
IndexedHeap <MSTVertex > q = new IndexedHeap <>(g .size ());
103
161
for (Vertex u : g ){
104
162
q .add (get (u ));
105
163
}
164
+
106
165
while (!q .isEmpty ()){
107
- MSTVertex u = q .poll ();
108
- u .seen = true ;
109
- wmst += u .d ;
110
- for (Edge e : g .incident (u .vertex )){
166
+ MSTVertex u = q .poll (); //get vertex u representing edge e(v,u) with min weight (v.d)
167
+ u .seen = true ; // this vertex is processed
168
+ wmst += u .d ; // update MST weight
169
+
170
+ for (Edge e : g .incident (u .vertex )){ // every edge e(u,v) outgoing of u
111
171
Vertex v = e .otherEnd (u .vertex );
172
+ //discard if v already processed or v already represented edge with less weight than e
112
173
if (!get (v ).seen && e .getWeight () < get (v ).d ){
174
+ // update weight and predecessor
113
175
get (v ).d = e .getWeight ();
114
176
get (v ).parent = u .vertex ;
177
+ //update priority queue
115
178
q .decreaseKey (get (v ));
116
179
}
117
180
}
118
181
}
119
182
return wmst ;
120
183
}
121
184
185
+ /**
186
+ * Prim2 (modification of Prim1)
187
+ * - maintain priority queue of vertex.
188
+ * - Store only the end vertex v representing edge e(u, v) in priority queue
189
+ * - v.d = w(e)
190
+ * - v.d is acts as a key in priority queue (see MSTVertex's compareTo(other MSTVertex))
191
+ * - There may exist duplicate vertices representing different edges.
192
+ * - Only the vertex with min weight is considered in future (this issue is solved in Prim3)
193
+ * @param s source vertex
194
+ * @return total weight of MST
195
+ */
122
196
public long prim2 (Vertex s ) {
123
197
algorithm = "PriorityQueue<Vertex>" ;
198
+ //initialization
124
199
initialize ();
125
200
get (s ).d = 0 ;
126
201
mst = new LinkedList <>();
127
- PriorityQueue <MSTVertex > q = new PriorityQueue <>();
202
+ PriorityQueue <MSTVertex > q = new PriorityQueue <>(); // priority queue to get remaining min weight edge to add to mst
128
203
q .add (get (s ));
129
204
130
205
while (!q .isEmpty ()){
131
- MSTVertex u = q .remove ();
206
+ MSTVertex u = q .remove (); // get edge with min weight. vertex u represents edge e(v,u)
132
207
if (!u .seen ){
133
208
u .seen = true ;
134
- wmst +=u .d ;
209
+ wmst +=u .d ; // w(e)
210
+
211
+ for (Edge e : g .incident (u .vertex )){ // edges (u,v) outgoing of u
212
+ Vertex v = e .otherEnd (u .vertex ); // other end of edge (u,v)
135
213
136
- for (Edge e : g .incident (u .vertex )){
137
- Vertex v = e .otherEnd (u .vertex );
214
+ // discard if v is already seen or v already represented edge e' with lesser weight then e
138
215
if (!get (v ).seen && e .getWeight () < get (v ).d ){
139
- MSTVertex dupV = new MSTVertex (get (v ));
140
- dupV .d = e .getWeight ();
141
- dupV .parent = u .vertex ;
142
- put (dupV .vertex , dupV ).seen = true ;
143
- q .add (dupV );
216
+ MSTVertex dupV = new MSTVertex (get (v )); // duplicate the old vertex
217
+ dupV .d = e .getWeight (); // set new lesser weight of edge
218
+ dupV .parent = u .vertex ; // now new v represents new edge
219
+ get (v ).seen = true ; // make old vertex seen so that it is never used here again
220
+ put (dupV .vertex , dupV ); // replace old vertex with new for future access
221
+ q .add (dupV ); // add to priority queue
144
222
}
145
223
}
146
224
@@ -150,35 +228,48 @@ public long prim2(Vertex s) {
150
228
return wmst ;
151
229
}
152
230
231
+ /**
232
+ * Prim1:
233
+ * - maintain priority queue of edges of G
234
+ * - remove smallest weight edge from queue and add it to MST if appropriate
235
+ * @param s
236
+ * @return
237
+ */
153
238
public long prim1 (Vertex s ) {
154
239
algorithm = "PriorityQueue<Edge>" ;
240
+ //initialization
155
241
initialize ();
156
242
get (s ).seen = true ;
157
243
mst = new LinkedList <>();
158
244
PriorityQueue <Edge > q = new PriorityQueue <>();
159
245
246
+ //add every edge incident to source to queue
160
247
for (Edge e : g .incident (s )){
161
248
q .add (e );
162
249
}
163
250
251
+ //while every edge is not processed
164
252
while (!q .isEmpty ()){
165
- Edge e = q .remove ();
166
- Vertex v = get (e .fromVertex ()).seen ? e .toVertex () : e .fromVertex ();
167
- if (get (v ).seen ) continue ;
253
+ Edge e = q .remove (); // extract min weight edge e(u,v) with u.seen = true
254
+ Vertex v = get (e .fromVertex ()).seen ? e .toVertex () : e .fromVertex (); // get v from e(u,v)
255
+ if (get (v ).seen ) continue ; // discard if other end is also processed
168
256
169
- get (v ).seen = true ;
170
- get (v ).parent = e .otherEnd (v );
171
- wmst += e .getWeight ();
257
+ get (v ).seen = true ; // this vertex is processed now
258
+ get (v ).parent = e .otherEnd (v ); // set its predecessor as u
259
+ wmst += e .getWeight (); // update weight
172
260
173
- for (Edge e2 : g .incident (v )){
174
- if (!get (e2 .otherEnd (v )).seen ){
175
- q .add (e2 );
261
+ for (Edge e1 : g .incident (v )){ // for every outgoing edge e1(v, u)
262
+ if (!get (e1 .otherEnd (v )).seen ){ // if u is not processed, meaning edge (v,u) is not processed, add to queue
263
+ q .add (e1 );
176
264
}
177
265
}
178
266
}
179
267
return wmst ;
180
268
}
181
269
270
+ /**
271
+ * Initialization process for all prim algorithms
272
+ */
182
273
void initialize (){
183
274
for (Vertex u : g ){
184
275
get (u ).seen = false ;
0 commit comments