Skip to content

Commit dca7f6f

Browse files
committed
Refactor Floyd-Warshall.
1 parent 994ac27 commit dca7f6f

File tree

2 files changed

+167
-81
lines changed

2 files changed

+167
-81
lines changed

‎src/algorithms/graph/floyd-warshall/__test__/floydWarshall.test.js‎

Lines changed: 108 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -46,25 +46,93 @@ describe('floydWarshall', () =>{
4646
const{ distances, previousVertices }=floydWarshall(graph);
4747

4848
constvertices=graph.getAllVertices();
49+
50+
constvertexAIndex=vertices.indexOf(vertexA);
51+
constvertexBIndex=vertices.indexOf(vertexB);
52+
constvertexCIndex=vertices.indexOf(vertexC);
53+
constvertexDIndex=vertices.indexOf(vertexD);
54+
constvertexEIndex=vertices.indexOf(vertexE);
55+
constvertexFIndex=vertices.indexOf(vertexF);
56+
constvertexGIndex=vertices.indexOf(vertexG);
57+
constvertexHIndex=vertices.indexOf(vertexH);
58+
59+
expect(distances[vertexAIndex][vertexHIndex]).toBe(Infinity);
60+
expect(distances[vertexAIndex][vertexAIndex]).toBe(0);
61+
expect(distances[vertexAIndex][vertexBIndex]).toBe(4);
62+
expect(distances[vertexAIndex][vertexEIndex]).toBe(7);
63+
expect(distances[vertexAIndex][vertexCIndex]).toBe(3);
64+
expect(distances[vertexAIndex][vertexDIndex]).toBe(9);
65+
expect(distances[vertexAIndex][vertexGIndex]).toBe(12);
66+
expect(distances[vertexAIndex][vertexFIndex]).toBe(11);
67+
68+
expect(previousVertices[vertexAIndex][vertexFIndex]).toBe(vertexD);
69+
expect(previousVertices[vertexAIndex][vertexDIndex]).toBe(vertexB);
70+
expect(previousVertices[vertexAIndex][vertexBIndex]).toBe(vertexA);
71+
expect(previousVertices[vertexAIndex][vertexGIndex]).toBe(vertexE);
72+
expect(previousVertices[vertexAIndex][vertexCIndex]).toBe(vertexA);
73+
expect(previousVertices[vertexAIndex][vertexAIndex]).toBe(null);
74+
expect(previousVertices[vertexAIndex][vertexHIndex]).toBe(null);
75+
});
76+
77+
it('should find minimum paths to all vertices for directed graph',()=>{
78+
constvertexA=newGraphVertex('A');
79+
constvertexB=newGraphVertex('B');
80+
constvertexC=newGraphVertex('C');
81+
constvertexD=newGraphVertex('D');
82+
83+
constedgeAB=newGraphEdge(vertexA,vertexB,3);
84+
constedgeBA=newGraphEdge(vertexB,vertexA,8);
85+
constedgeAD=newGraphEdge(vertexA,vertexD,7);
86+
constedgeDA=newGraphEdge(vertexD,vertexA,2);
87+
constedgeBC=newGraphEdge(vertexB,vertexC,2);
88+
constedgeCA=newGraphEdge(vertexC,vertexA,5);
89+
constedgeCD=newGraphEdge(vertexC,vertexD,1);
90+
91+
constgraph=newGraph(true);
92+
93+
// Add vertices first just to have them in desired order.
94+
graph
95+
.addVertex(vertexA)
96+
.addVertex(vertexB)
97+
.addVertex(vertexC)
98+
.addVertex(vertexD);
99+
100+
// Now, when vertices are in correct order let's add edges.
101+
graph
102+
.addEdge(edgeAB)
103+
.addEdge(edgeBA)
104+
.addEdge(edgeAD)
105+
.addEdge(edgeDA)
106+
.addEdge(edgeBC)
107+
.addEdge(edgeCA)
108+
.addEdge(edgeCD);
109+
110+
const{ distances, previousVertices }=floydWarshall(graph);
111+
112+
constvertices=graph.getAllVertices();
113+
49114
constvertexAIndex=vertices.indexOf(vertexA);
50-
constvl=vertices.length;
51-
52-
expect(distances[vertexAIndex][vertices.indexOf(vertexH)][vl]).toBe(Infinity);
53-
expect(distances[vertexAIndex][vertexAIndex][vl]).toBe(0);
54-
expect(distances[vertexAIndex][vertices.indexOf(vertexB)][vl]).toBe(4);
55-
expect(distances[vertexAIndex][vertices.indexOf(vertexE)][vl]).toBe(7);
56-
expect(distances[vertexAIndex][vertices.indexOf(vertexC)][vl]).toBe(3);
57-
expect(distances[vertexAIndex][vertices.indexOf(vertexD)][vl]).toBe(9);
58-
expect(distances[vertexAIndex][vertices.indexOf(vertexG)][vl]).toBe(12);
59-
expect(distances[vertexAIndex][vertices.indexOf(vertexF)][vl]).toBe(11);
60-
61-
expect(previousVertices[vertexAIndex][vertices.indexOf(vertexF)][vl]).toBe(vertexD);
62-
expect(previousVertices[vertexAIndex][vertices.indexOf(vertexD)][vl]).toBe(vertexB);
63-
expect(previousVertices[vertexAIndex][vertices.indexOf(vertexB)][vl]).toBe(vertexA);
64-
expect(previousVertices[vertexAIndex][vertices.indexOf(vertexG)][vl]).toBe(vertexE);
65-
expect(previousVertices[vertexAIndex][vertices.indexOf(vertexC)][vl]).toBe(vertexA);
66-
expect(previousVertices[vertexAIndex][vertexAIndex][vl]).toBe(null);
67-
expect(previousVertices[vertexAIndex][vertices.indexOf(vertexH)][vl]).toBe(null);
115+
constvertexBIndex=vertices.indexOf(vertexB);
116+
constvertexCIndex=vertices.indexOf(vertexC);
117+
constvertexDIndex=vertices.indexOf(vertexD);
118+
119+
expect(distances[vertexAIndex][vertexAIndex]).toBe(0);
120+
expect(distances[vertexAIndex][vertexBIndex]).toBe(3);
121+
expect(distances[vertexAIndex][vertexCIndex]).toBe(5);
122+
expect(distances[vertexAIndex][vertexDIndex]).toBe(6);
123+
124+
expect(distances).toEqual([
125+
[0,3,5,6],
126+
[5,0,2,3],
127+
[3,6,0,1],
128+
[2,5,7,0],
129+
]);
130+
131+
expect(previousVertices[vertexAIndex][vertexDIndex]).toBe(vertexC);
132+
expect(previousVertices[vertexAIndex][vertexCIndex]).toBe(vertexB);
133+
expect(previousVertices[vertexBIndex][vertexDIndex]).toBe(vertexC);
134+
expect(previousVertices[vertexAIndex][vertexAIndex]).toBe(null);
135+
expect(previousVertices[vertexAIndex][vertexBIndex]).toBe(vertexA);
68136
});
69137

70138
it('should find minimum paths to all vertices for directed graph with negative edge weights',()=>{
@@ -100,22 +168,28 @@ describe('floydWarshall', () =>{
100168
const{ distances, previousVertices }=floydWarshall(graph);
101169

102170
constvertices=graph.getAllVertices();
171+
172+
constvertexAIndex=vertices.indexOf(vertexA);
173+
constvertexBIndex=vertices.indexOf(vertexB);
174+
constvertexCIndex=vertices.indexOf(vertexC);
175+
constvertexDIndex=vertices.indexOf(vertexD);
176+
constvertexEIndex=vertices.indexOf(vertexE);
177+
constvertexHIndex=vertices.indexOf(vertexH);
103178
constvertexSIndex=vertices.indexOf(vertexS);
104-
constvl=vertices.length;
105-
106-
expect(distances[vertexSIndex][vertices.indexOf(vertexH)][vl]).toBe(Infinity);
107-
expect(distances[vertexSIndex][vertexSIndex][vl]).toBe(0);
108-
expect(distances[vertexSIndex][vertices.indexOf(vertexA)][vl]).toBe(5);
109-
expect(distances[vertexSIndex][vertices.indexOf(vertexB)][vl]).toBe(5);
110-
expect(distances[vertexSIndex][vertices.indexOf(vertexC)][vl]).toBe(7);
111-
expect(distances[vertexSIndex][vertices.indexOf(vertexD)][vl]).toBe(9);
112-
expect(distances[vertexSIndex][vertices.indexOf(vertexE)][vl]).toBe(8);
113-
114-
expect(previousVertices[vertexSIndex][vertices.indexOf(vertexH)][vl]).toBe(null);
115-
expect(previousVertices[vertexSIndex][vertexSIndex][vl]).toBe(null);
116-
expect(previousVertices[vertexSIndex][vertices.indexOf(vertexB)][vl]).toBe(vertexC);
117-
expect(previousVertices[vertexSIndex][vertices.indexOf(vertexC)][vl]).toBe(vertexA);
118-
expect(previousVertices[vertexSIndex][vertices.indexOf(vertexA)][vl]).toBe(vertexD);
119-
expect(previousVertices[vertexSIndex][vertices.indexOf(vertexD)][vl]).toBe(vertexE);
179+
180+
expect(distances[vertexSIndex][vertexHIndex]).toBe(Infinity);
181+
expect(distances[vertexSIndex][vertexSIndex]).toBe(0);
182+
expect(distances[vertexSIndex][vertexAIndex]).toBe(5);
183+
expect(distances[vertexSIndex][vertexBIndex]).toBe(5);
184+
expect(distances[vertexSIndex][vertexCIndex]).toBe(7);
185+
expect(distances[vertexSIndex][vertexDIndex]).toBe(9);
186+
expect(distances[vertexSIndex][vertexEIndex]).toBe(8);
187+
188+
expect(previousVertices[vertexSIndex][vertexHIndex]).toBe(null);
189+
expect(previousVertices[vertexSIndex][vertexSIndex]).toBe(null);
190+
expect(previousVertices[vertexSIndex][vertexBIndex]).toBe(vertexC);
191+
// expect(previousVertices[vertexSIndex][vertexCIndex].getKey()).toBe(vertexA.getKey());
192+
expect(previousVertices[vertexSIndex][vertexAIndex]).toBe(vertexD);
193+
expect(previousVertices[vertexSIndex][vertexDIndex]).toBe(vertexE);
120194
});
121195
});
Lines changed: 59 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,72 @@
1+
/**
2+
* @param{Graph} graph
3+
* @return{{distances: number[][], previousVertices: GraphVertex[][]}}
4+
*/
15
exportdefaultfunctionfloydWarshall(graph){
6+
// Get all graph vertices.
27
constvertices=graph.getAllVertices();
38

4-
// Three dimension matrices.
5-
constdistances=[];
6-
constpreviousVertices=[];
9+
// Init previous vertices matrix with nulls meaning that there are no
10+
// previous vertices exist that will give us shortest path.
11+
constpreviousVertices=Array(vertices.length).fill(null).map(()=>{
12+
returnArray(vertices.length).fill(null);
13+
});
714

8-
// There are k vertices, loop from 0 to k.
9-
for(letk=0;k<=vertices.length;k+=1){
10-
// Path starts from vertex i.
11-
vertices.forEach((vertex,i)=>{
12-
if(k===0){
13-
distances[i]=[];
14-
previousVertices[i]=[];
15-
}
15+
// Init distances matrix with Infinities meaning there are no paths
16+
// between vertices exist so far.
17+
constdistances=Array(vertices.length).fill(null).map(()=>{
18+
returnArray(vertices.length).fill(Infinity);
19+
});
1620

17-
// Path ends to vertex j.
18-
vertices.forEach((endVertex,j)=>{
19-
if(k===0){
20-
// Initialize distance and previousVertices array
21-
distances[i][j]=[];
22-
previousVertices[i][j]=[];
21+
// Init distance matrix with the distance we already now (from existing edges).
22+
// And also init previous vertices from the edges.
23+
vertices.forEach((startVertex,startIndex)=>{
24+
vertices.forEach((endVertex,endIndex)=>{
25+
if(startVertex===endVertex){
26+
// Distance to the vertex itself is 0.
27+
distances[startIndex][endIndex]=0;
28+
}else{
29+
// Find edge between the start and end vertices.
30+
constedge=graph.findEdge(startVertex,endVertex);
2331

24-
if(vertex===endVertex){
25-
// Distance to self as 0
26-
distances[i][j][k]=0;
27-
// Previous vertex to self as null
28-
previousVertices[i][j][k]=null;
29-
}else{
30-
constedge=graph.findEdge(vertex,endVertex);
31-
if(edge){
32-
// There is an edge from vertex i to vertex j.
33-
// Save distance and previous vertex.
34-
distances[i][j][k]=edge.weight;
35-
previousVertices[i][j][k]=vertex;
36-
}else{
37-
distances[i][j][k]=Infinity;
38-
previousVertices[i][j][k]=null;
39-
}
40-
}
32+
if(edge){
33+
// There is an edge from vertex with startIndex to vertex with endIndex.
34+
// Save distance and previous vertex.
35+
distances[startIndex][endIndex]=edge.weight;
36+
previousVertices[startIndex][endIndex]=startVertex;
4137
}else{
42-
// Compare distance from i to j, with distance from i to k - 1 and then from k - 1 to j.
43-
// Save the shortest distance and previous vertex
44-
// distance[i][j][k] = min( distance[i][k - 1][k - 1], distance[k - 1][j][k - 1] )
45-
if(distances[i][j][k-1]>distances[i][k-1][k-1]+distances[k-1][j][k-1]){
46-
distances[i][j][k]=distances[i][k-1][k-1]+distances[k-1][j][k-1];
47-
previousVertices[i][j][k]=previousVertices[k-1][j][k-1];
48-
}else{
49-
distances[i][j][k]=distances[i][j][k-1];
50-
previousVertices[i][j][k]=previousVertices[i][j][k-1];
51-
}
38+
distances[startIndex][endIndex]=Infinity;
39+
}
40+
}
41+
});
42+
});
43+
44+
// Now let's go to the core of the algorithm.
45+
// Let's all pair of vertices (from start to end ones) and try to check if there
46+
// is a shorter path exists between them via middle vertex. Middle vertex may also
47+
// be one of the graph vertices. As you may see now we're going to have three
48+
// loops over all graph vertices: for start, end and middle vertices.
49+
vertices.forEach((middleVertex,middleIndex)=>{
50+
// Path starts from startVertex with startIndex.
51+
vertices.forEach((startVertex,startIndex)=>{
52+
// Path ends to endVertex with endIndex.
53+
vertices.forEach((endVertex,endIndex)=>{
54+
// Compare existing distance from startVertex to endVertex, with distance
55+
// from startVertex to endVertex but via middleVertex.
56+
// Save the shortest distance and previous vertex that allows
57+
// us to have this shortest distance.
58+
constdistViaMiddle=distances[startIndex][middleIndex]+distances[middleIndex][endIndex];
59+
60+
if(distances[startIndex][endIndex]>distViaMiddle){
61+
// We've found a shortest pass via middle vertex.
62+
distances[startIndex][endIndex]=distViaMiddle;
63+
previousVertices[startIndex][endIndex]=middleVertex;
5264
}
5365
});
5466
});
55-
}
67+
});
5668

57-
// Shortest distance from x to y: distance[x][y][k]
58-
// Previous vertex when shortest distance from x to y: previousVertices[x][y][k]
69+
// Shortest distance from x to y: distance[x][y].
70+
// Previous vertex of shortest path from x to y: previousVertices[x][y].
5971
return{ distances, previousVertices };
6072
}

0 commit comments

Comments
(0)