Skip to content

Commit 93ce399

Browse files
committed
chapter 13: graphs
1 parent 6d1b9f2 commit 93ce399

16 files changed

+858
-0
lines changed

src/13-graph/01-airline-system.js

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// src/13-graph/01-airline-system.js
2+
3+
// import the Graph class
4+
const Graph = require('./graph');
5+
6+
const airline = new Graph();
7+
8+
const airports = 'MCO TPA JFK LAX SFO'.split(' ');
9+
10+
airports.forEach(airport =>
11+
airline.addVertex(airport)
12+
);
13+
14+
airline.addEdge('MCO', 'JFK');
15+
airline.addEdge('MCO', 'LAX');
16+
airline.addEdge('TPA', 'JFK');
17+
airline.addEdge('TPA', 'LAX');
18+
airline.addEdge('JFK', 'LAX');
19+
airline.addEdge('JFK', 'SFO');
20+
airline.addEdge('LAX', 'SFO');
21+
22+
console.log(airline.toString());
23+
24+
// Output:
25+
// MCO -> JFK LAX
26+
// TPA -> JFK LAX
27+
// JFK -> MCO TPA LAX SFO
28+
// LAX -> MCO TPA JFK SFO
29+
// SFO -> JFK LAX
30+
31+
// to see the output of this file use the command: node src/13-graph/01-airline-system.js

src/13-graph/02-using-bfs.js

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// src/13-graph/02-using-bfs.js
2+
3+
const Graph = require('./graph');
4+
const { breadthFirstSearch, bfsShortestPath} = require('./bfs');
5+
6+
const airline = new Graph();
7+
8+
const airports = 'SEA SFO LAX LAS DEN DFW STL MDW JFK ATL MCO MIA'.split(' ');
9+
10+
airports.forEach(airport =>
11+
airline.addVertex(airport)
12+
);
13+
14+
airline.addEdge('SEA', 'SFO');
15+
airline.addEdge('SEA', 'DEN');
16+
airline.addEdge('SEA', 'MDW');
17+
airline.addEdge('SFO', 'LAX');
18+
airline.addEdge('LAX', 'LAS');
19+
airline.addEdge('DEN', 'DFW');
20+
airline.addEdge('DEN', 'STL');
21+
airline.addEdge('STL', 'MDW');
22+
airline.addEdge('STL', 'MCO');
23+
airline.addEdge('MDW', 'ATL');
24+
airline.addEdge('MDW', 'JFK');
25+
airline.addEdge('ATL', 'JFK');
26+
airline.addEdge('JFK', 'MCO');
27+
airline.addEdge('JFK', 'MIA');
28+
29+
console.log(airline.toString());
30+
31+
// Output:
32+
// SEA -> SFO DEN MDW
33+
// SFO -> SEA LAX
34+
// LAX -> SFO LAS
35+
// LAS -> LAX
36+
// DEN -> SEA DFW STL
37+
// DFW -> DEN
38+
// STL -> DEN MDW MCO
39+
// MDW -> SEA STL ATL JFK
40+
// JFK -> MDW ATL MCO MIA
41+
// ATL -> MDW JFK
42+
// MCO -> STL JFK
43+
// MIA -> JFK
44+
45+
console.log('--- BFS ---');
46+
47+
const printAirport = (value) => console.log('Visited airport: ' + value);
48+
49+
breadthFirstSearch(airline,'SEA', printAirport);
50+
51+
// Output:
52+
// --- BFS ---
53+
// Visited airport: SEA
54+
// Visited airport: SFO
55+
// Visited airport: DEN
56+
// Visited airport: MDW
57+
// Visited airport: LAX
58+
// Visited airport: DFW
59+
// Visited airport: STL
60+
// Visited airport: ATL
61+
// Visited airport: JFK
62+
// Visited airport: LAS
63+
// Visited airport: MCO
64+
// Visited airport: MIA
65+
66+
console.log('--- BFS Shortest Path ---');
67+
68+
const shortestPath = bfsShortestPath(airline, 'SEA');
69+
console.log(shortestPath);
70+
71+
// { distances: { SEA: 0, SFO: 1, LAX: 2, LAS: 3, DEN: 1, DFW: 2, STL: 2, MDW: 1, JFK: 2, ATL: 2, MCO: 3, MIA: 3 },
72+
// predecessors: { SEA: null, SFO: 'SEA', LAX: 'SFO', LAS: 'LAX', DEN: 'SEA', DFW: 'DEN', STL: 'DEN', MDW: 'SEA', JFK: 'MDW', ATL: 'MDW', MCO: 'STL', MIA: 'JFK'}
73+
// }
74+
75+
// find the shortest path from SEA to JFK
76+
let path = [];
77+
for (let v = 'JFK'; v !== 'SEA'; v = shortestPath.predecessors[v]) {
78+
path.push(v);
79+
}
80+
path.push('SEA');
81+
path.reverse();
82+
83+
console.log('Shortest path from SEA to JFK: ' + path.join(' -> '));
84+
85+
// Shortest path from SEA to JFK: SEA -> MDW -> JFK
86+
87+
// to see the output of this file use the command: node src/13-graph/02-using-bfs.js

src/13-graph/03-using-dfs.js

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// src/13-graph/03-using-dfs.js
2+
3+
const Graph = require('./graph');
4+
const { depthFirstSearch, enhancedDepthFirstSearch } = require('./dfs');
5+
6+
const caveSystem = new Graph();
7+
8+
const caves = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'];
9+
10+
caves.forEach(cave => caveSystem.addVertex(cave));
11+
12+
13+
caveSystem.addEdge('A', 'B');
14+
caveSystem.addEdge('A', 'C');
15+
caveSystem.addEdge('A', 'D');
16+
caveSystem.addEdge('C', 'D');
17+
caveSystem.addEdge('C', 'G');
18+
caveSystem.addEdge('D', 'G');
19+
caveSystem.addEdge('D', 'H');
20+
caveSystem.addEdge('B', 'E');
21+
caveSystem.addEdge('B', 'F');
22+
caveSystem.addEdge('E', 'I');
23+
24+
console.log('********* DFS - cave ***********');
25+
depthFirstSearch(caveSystem, (cave) => console.log('Visited cave:',cave));
26+
27+
// ********* DFS - cave ***********
28+
// Visited cave: A
29+
// Visited cave: B
30+
// Visited cave: E
31+
// Visited cave: I
32+
// Visited cave: F
33+
// Visited cave: C
34+
// Visited cave: D
35+
// Visited cave: G
36+
// Visited cave: H
37+
38+
console.log('********* Enhanced DFS - cave ***********');
39+
const result = enhancedDepthFirstSearch(caveSystem);
40+
41+
console.log(result);
42+
43+
console.log('********* Topological sort using DFS ***********');
44+
45+
const tasks = new Graph(true); // this is a directed graph
46+
['A', 'B', 'C', 'D', 'E', 'F'].forEach(task => tasks.addVertex(task));
47+
// add the arrows, task dependencies:
48+
tasks.addEdge('A', 'C');
49+
tasks.addEdge('A', 'D');
50+
tasks.addEdge('B', 'D');
51+
tasks.addEdge('B', 'E');
52+
tasks.addEdge('C', 'F');
53+
tasks.addEdge('F', 'E');
54+
55+
// DFS traversal
56+
const dfsTasks = enhancedDepthFirstSearch(tasks);
57+
console.log(dfsTasks);
58+
// {
59+
// discovery: { A: 1, B: 11, C: 2, D: 8, E: 4, F: 3 },
60+
// finished: { A: 10, B: 12, C: 7, D: 9, E: 5, F: 6 },
61+
// predecessors: { A: null, B: null, C: 'A', D: 'A', E: 'F', F: 'C' }
62+
// }
63+
64+
// sort tasks in decreasing order of finish time
65+
// dfsTasks.finished = { A: 10, B: 12, C: 7, D: 9, E: 5, F: 6 }
66+
const sortedTasks = Object.keys(dfsTasks.finished).sort((a, b) => dfsTasks.finished[b] - dfsTasks.finished[a]);
67+
console.log(sortedTasks);
68+
// [ 'B', 'A', 'D', 'C', 'F', 'E' ]
69+
70+
// to see the output of this file use the command: node src/13-graph/03-using-dfs.js

src/13-graph/04-using-dijkstra.js

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// src/13-graph/04-using-dijkstra.js
2+
3+
const Graph = require('./graph');
4+
const dijkstra = require('./dijkstra');
5+
6+
const flightCosts = [
7+
// SEA, MDW, DEN, MCO, STL, JFK, ATL
8+
[0, 300, 220, 1000, 0, 0, 0], // SEA
9+
[300, 0, 0, 0, 50, 210, 190], // MDW
10+
[220, 0, 0, 0, 350, 0, 0], // DEN
11+
[1000, 0, 0, 0, 150, 250, 0], // MCO
12+
[0, 50, 350, 150, 0, 0, 0], // STL
13+
[0, 210, 0, 250, 0, 0, 200], // JFK
14+
[0, 190, 0, 0, 0, 200, 0], // ATL
15+
];
16+
17+
console.log('********* Dijkstra\'s Algorithm - Shortest Path ***********');
18+
19+
const prices = dijkstra(flightCosts, 0); // SEA
20+
// prices output:
21+
// {
22+
// distances: [
23+
// 0, 300, 220,
24+
// 500, 350, 510,
25+
// 490
26+
// ],
27+
// predecessors: {
28+
// '0': [ 0 ],
29+
// '1': [ 0, 1 ],
30+
// '2': [ 0, 2 ],
31+
// '3': [ 0, 1, 4, 3 ],
32+
// '4': [ 0, 1, 4 ],
33+
// '5': [ 0, 1, 5 ],
34+
// '6': [ 0, 1, 6 ]
35+
// }
36+
// }
37+
console.log('Prices from SEA to all airports:');
38+
const airports = ['SEA', 'MDW', 'DEN', 'MCO', 'STL', 'JFK', 'ATL'];
39+
for (let i = 1; i < airports.length; i++) {
40+
const flights = prices.predecessors[i].map(airport => airports[airport]).join(' -> ');
41+
console.log(`SEA -> ${airports[i]}: $${prices.distances[i]} via ${flights}`);
42+
}
43+
// Prices from SEA to all airports:
44+
// SEA -> MDW: $300 via SEA -> MDW
45+
// SEA -> DEN: $220 via SEA -> DEN
46+
// SEA -> MCO: $500 via SEA -> MDW -> STL -> MCO
47+
// SEA -> STL: $350 via SEA -> MDW -> STL
48+
// SEA -> JFK: $510 via SEA -> MDW -> JFK
49+
// SEA -> ATL: $490 via SEA -> MDW -> ATL
50+
51+
// to see the output of this file use the command: node src/13-graph/04-using-dijkstra.js
+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// src/13-graph/05-using-floyd-warshall.js
2+
3+
const floydWarshall = require('./floyd-warshall');
4+
5+
const INF = Infinity;
6+
const flightCosts = [
7+
// SEA, MDW, DEN, MCO, STL, JFK, ATL
8+
[INF, 300, 220, 1000, INF, INF, INF], // SEA
9+
[300, INF, INF, INF, 50, 210, 190], // MDW
10+
[220, INF, INF, INF, 350, INF, INF], // DEN
11+
[1000, INF, INF, INF, 150, 250, INF], // MCO
12+
[INF, 50, 350, 150, INF, INF, INF], // STL
13+
[INF, 210, INF, 250, INF, INF, 200], // JFK
14+
[INF, 190, INF, INF, INF, 200, INF], // ATL
15+
];
16+
17+
console.log('********* Floyd-Warshall Algorithm - Shortest Path ***********');
18+
19+
const distances = floydWarshall(flightCosts);
20+
console.log('Distances between all airports:');
21+
22+
const airports = ['SEA', 'MDW', 'DEN', 'MCO', 'STL', 'JFK', 'ATL'];
23+
console.table(airports.map((airport, i) => {
24+
return airports.reduce((acc, dest, j) => {
25+
acc[dest] = distances[i][j];
26+
return acc;
27+
}, {});
28+
}));
29+
30+
// ┌─────────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐
31+
// │ Airport │ SEA │ MDW │ DEN │ MCO │ STL │ JFK │ ATL │
32+
// ├─────────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┤
33+
// │ SEA │ 0 │ 300 │ 220 │ 500 │ 350 │ 510 │ 490 │
34+
// │ MDW │ 300 │ 0 │ 400 │ 200 │ 50 │ 210 │ 190 │
35+
// │ DEN │ 220 │ 400 │ 0 │ 500 │ 350 │ 610 │ 590 │
36+
// │ MCO │ 500 │ 200 │ 500 │ 0 │ 150 │ 250 │ 390 │
37+
// │ STL │ 350 │ 50 │ 350 │ 150 │ 0 │ 260 │ 240 │
38+
// │ JFK │ 510 │ 210 │ 610 │ 250 │ 260 │ 0 │ 200 │
39+
// │ ATL │ 490 │ 190 │ 590 │ 390 │ 240 │ 200 │ 0 │
40+
// └─────────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘
41+
42+
// to see the output of this file use the command: node src/13-graph/05-using-floyd-warshall.js

src/13-graph/06-using-prim.js

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// src/13-graph/06-using-prim.js
2+
3+
const prim = require('./prim');
4+
5+
const cityNames = ['Erebor', 'Rivendell', 'Hobbiton', 'Isengard', 'Rohan', 'Lothlorien'];
6+
7+
const cities = [
8+
[0, 2, 4, 0, 0, 0],
9+
[2, 0, 2, 4, 2, 0],
10+
[4, 2, 0, 0, 3, 0],
11+
[0, 4, 0, 0, 3, 2],
12+
[0, 2, 3, 3, 0, 2],
13+
[0, 0, 0, 2, 2, 0]
14+
];
15+
16+
const mst = prim(cities);
17+
console.log('Minimum Spanning Tree:', mst);
18+
19+
// [ -1, 0, 1, 5, 1, 4 ]
20+
21+
// to see the output of this file use the command: node src/13-graph/06-using-prim.js

src/13-graph/07-using-kruskal.js

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// src/13-graph/07-using-kruskal.js
2+
3+
const kruskal = require('./kruskal');
4+
5+
const cityNames = ['Erebor', 'Rivendell', 'Hobbiton', 'Isengard', 'Rohan', 'Lothlorien'];
6+
7+
const cities = [
8+
[0, 2, 4, 0, 0, 0],
9+
[2, 0, 2, 4, 2, 0],
10+
[4, 2, 0, 0, 3, 0],
11+
[0, 4, 0, 0, 3, 2],
12+
[0, 2, 3, 3, 0, 2],
13+
[0, 0, 0, 2, 2, 0]
14+
];
15+
16+
const mst = kruskal(cities);
17+
18+
console.log('Minimum Spanning Tree with Kruskal:', mst);
19+
20+
// [ [ 0, 1 ], [ 1, 2 ], [ 1, 4 ], [ 3, 5 ], [ 4, 5 ] ]
21+
22+
// to see the output of this file use the command: node src/13-graph/07-using-kruskal.js

0 commit comments

Comments
 (0)