Skip to content

Commit 9f8fd33

Browse files
vivaxytrekhleb
authored andcommitted
feat(algorithms): ✨Add Floyd-Warshall (trekhleb#97)
1 parent 3e8540b commit 9f8fd33

File tree

6 files changed

+194
-5
lines changed

6 files changed

+194
-5
lines changed

‎README.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,8 @@ a set of rules that precisely define a sequence of operations.
113113
*`A`[Hamiltonian Cycle](src/algorithms/graph/hamiltonian-cycle) - Visit every vertex exactly once
114114
*`A`[Strongly Connected Components](src/algorithms/graph/strongly-connected-components) - Kosaraju's algorithm
115115
*`A`[Travelling Salesman Problem](src/algorithms/graph/travelling-salesman) - shortest possible route that visits each city and returns to the origin city
116-
***Uncategorized**
116+
*`A`[Floyd-Warshall algorithm](src/algorithms/graph/floyd-warshall) - a single execution of the algorithm will find the lengths (summed weights) of shortest paths between all pairs of vertices
117+
***Uncategorized**
117118
*`B`[Tower of Hanoi](src/algorithms/uncategorized/hanoi-tower)
118119
*`B`[Square Matrix Rotation](src/algorithms/uncategorized/square-matrix-rotation) - in-place algorithm
119120
*`B`[Jump Game](src/algorithms/uncategorized/jump-game) - backtracking, dynamic programming (top-down + bottom-up) and greedy examples

‎README.zh-CN.md‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ _Read this in other languages:_
6969
*[归并排序](src/algorithms/sorting/merge-sort)
7070
*[快速排序](src/algorithms/sorting/quick-sort)
7171
*[希尔排序](src/algorithms/sorting/shell-sort)
72-
*****
72+
*****
7373
*[深度优先搜索](src/algorithms/tree/depth-first-search) (DFS)
7474
*[广度优先搜索](src/algorithms/tree/breadth-first-search) (BFS)
7575
*****
@@ -87,7 +87,8 @@ _Read this in other languages:_
8787
*[哈密顿图](src/algorithms/graph/hamiltonian-cycle) - 恰好访问每个顶点一次
8888
*[强连通分量](src/algorithms/graph/strongly-connected-components) - Kosaraju算法
8989
*[旅行推销员问题](src/algorithms/graph/travelling-salesman) - 尽可能以最短的路线访问每个城市并返回原始城市
90-
***未分类**
90+
*[Floyd-Warshall algorithm](src/algorithms/graph/floyd-warshall) - 一次循环可以找出所有顶点之间的最短路径
91+
***未分类**
9192
*[汉诺塔](src/algorithms/uncategorized/hanoi-tower)
9293
*[八皇后问题](src/algorithms/uncategorized/n-queens)
9394
*[骑士巡逻](src/algorithms/uncategorized/knight-tour)

‎README.zh-TW.md‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ _Read this in other languages:_
6868
*[合併排序](src/algorithms/sorting/merge-sort)
6969
*[快速排序](src/algorithms/sorting/quick-sort)
7070
*[希爾排序](src/algorithms/sorting/shell-sort)
71-
*****
71+
*****
7272
*[深度優先搜尋](src/algorithms/tree/depth-first-search) (DFS)
7373
*[廣度優先搜尋](src/algorithms/tree/breadth-first-search) (BFS)
7474
*****
@@ -86,7 +86,8 @@ _Read this in other languages:_
8686
*[漢彌爾頓環](src/algorithms/graph/hamiltonian-cycle) - Visit every vertex exactly once
8787
*[強連通組件](src/algorithms/graph/strongly-connected-components) - Kosaraju's algorithm
8888
*[旅行推銷員問題](src/algorithms/graph/travelling-salesman) - shortest possible route that visits each city and returns to the origin city
89-
***未分類**
89+
*[Floyd-Warshall algorithm](src/algorithms/graph/floyd-warshall) - 一次循环可以找出所有頂點之间的最短路徑
90+
***未分類**
9091
*[河內塔](src/algorithms/uncategorized/hanoi-tower)
9192
*[N-皇后問題](src/algorithms/uncategorized/n-queens)
9293
*[騎士走棋盤](src/algorithms/uncategorized/knight-tour)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Floyd–Warshall algorithm
2+
3+
## References
4+
5+
-[Wikipedia](https://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm)
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
importGraphVertexfrom'../../../../data-structures/graph/GraphVertex';
2+
importGraphEdgefrom'../../../../data-structures/graph/GraphEdge';
3+
importGraphfrom'../../../../data-structures/graph/Graph';
4+
importfloydWarshallfrom'../floydWarshall';
5+
6+
describe('floydWarshall',()=>{
7+
it('should find minimum paths to all vertices for undirected graph',()=>{
8+
constvertexA=newGraphVertex('A');
9+
constvertexB=newGraphVertex('B');
10+
constvertexC=newGraphVertex('C');
11+
constvertexD=newGraphVertex('D');
12+
constvertexE=newGraphVertex('E');
13+
constvertexF=newGraphVertex('F');
14+
constvertexG=newGraphVertex('G');
15+
constvertexH=newGraphVertex('H');
16+
17+
constedgeAB=newGraphEdge(vertexA,vertexB,4);
18+
constedgeAE=newGraphEdge(vertexA,vertexE,7);
19+
constedgeAC=newGraphEdge(vertexA,vertexC,3);
20+
constedgeBC=newGraphEdge(vertexB,vertexC,6);
21+
constedgeBD=newGraphEdge(vertexB,vertexD,5);
22+
constedgeEC=newGraphEdge(vertexE,vertexC,8);
23+
constedgeED=newGraphEdge(vertexE,vertexD,2);
24+
constedgeDC=newGraphEdge(vertexD,vertexC,11);
25+
constedgeDG=newGraphEdge(vertexD,vertexG,10);
26+
constedgeDF=newGraphEdge(vertexD,vertexF,2);
27+
constedgeFG=newGraphEdge(vertexF,vertexG,3);
28+
constedgeEG=newGraphEdge(vertexE,vertexG,5);
29+
30+
constgraph=newGraph();
31+
graph
32+
.addVertex(vertexH)
33+
.addEdge(edgeAB)
34+
.addEdge(edgeAE)
35+
.addEdge(edgeAC)
36+
.addEdge(edgeBC)
37+
.addEdge(edgeBD)
38+
.addEdge(edgeEC)
39+
.addEdge(edgeED)
40+
.addEdge(edgeDC)
41+
.addEdge(edgeDG)
42+
.addEdge(edgeDF)
43+
.addEdge(edgeFG)
44+
.addEdge(edgeEG);
45+
46+
const{ distances, previousVertices }=floydWarshall(graph);
47+
48+
constvertices=graph.getAllVertices();
49+
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);
68+
});
69+
70+
it('should find minimum paths to all vertices for directed graph with negative edge weights',()=>{
71+
constvertexS=newGraphVertex('S');
72+
constvertexE=newGraphVertex('E');
73+
constvertexA=newGraphVertex('A');
74+
constvertexD=newGraphVertex('D');
75+
constvertexB=newGraphVertex('B');
76+
constvertexC=newGraphVertex('C');
77+
constvertexH=newGraphVertex('H');
78+
79+
constedgeSE=newGraphEdge(vertexS,vertexE,8);
80+
constedgeSA=newGraphEdge(vertexS,vertexA,10);
81+
constedgeED=newGraphEdge(vertexE,vertexD,1);
82+
constedgeDA=newGraphEdge(vertexD,vertexA,-4);
83+
constedgeDC=newGraphEdge(vertexD,vertexC,-1);
84+
constedgeAC=newGraphEdge(vertexA,vertexC,2);
85+
constedgeCB=newGraphEdge(vertexC,vertexB,-2);
86+
constedgeBA=newGraphEdge(vertexB,vertexA,1);
87+
88+
constgraph=newGraph(true);
89+
graph
90+
.addVertex(vertexH)
91+
.addEdge(edgeSE)
92+
.addEdge(edgeSA)
93+
.addEdge(edgeED)
94+
.addEdge(edgeDA)
95+
.addEdge(edgeDC)
96+
.addEdge(edgeAC)
97+
.addEdge(edgeCB)
98+
.addEdge(edgeBA);
99+
100+
const{ distances, previousVertices }=floydWarshall(graph);
101+
102+
constvertices=graph.getAllVertices();
103+
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);
120+
});
121+
});
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
exportdefaultfunctionfloydWarshall(graph){
2+
constvertices=graph.getAllVertices();
3+
4+
// Three dimension matrices.
5+
constdistances=[];
6+
constpreviousVertices=[];
7+
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+
}
16+
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]=[];
23+
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+
}
41+
}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+
}
52+
}
53+
});
54+
});
55+
}
56+
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]
59+
return{ distances, previousVertices };
60+
}

0 commit comments

Comments
(0)