Skip to content

Commit 0d96b23

Browse files
committed
Add Johnson's Algorithm and Refactoring Vertex Interface Weight
1 parent 51a1789 commit 0d96b23

File tree

4 files changed

+170
-88
lines changed

4 files changed

+170
-88
lines changed

data-structures/graph/graph.js

Lines changed: 80 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ const minHeap_1 = __importDefault(require("../heaps/minHeap"));
1010
const listSet_1 = __importDefault(require("../disjoint-sets/listSet"));
1111
const forestSet_1 = __importDefault(require("../disjoint-sets/forestSet"));
1212
const fs_1 = __importDefault(require("fs"));
13-
const vertex_1 = require("./vertex");
1413
// Returns a random number between [min,max)
1514
const random = (min, max) => {
1615
return Math.floor(Math.random() * (max - min)) + min;
@@ -27,20 +26,10 @@ class Graph {
2726
for (let [u, vertexList] of this.list) {
2827
for (let v of vertexList) {
2928
if (!this.directed) {
30-
if (vertex_1.isWeighted(v)) {
31-
console.log(`${u} - ${v.node} - ${v.weight}`);
32-
}
33-
else {
34-
console.log(`${u} - ${v.node}`);
35-
}
29+
console.log(`${u} - ${v.node} - ${v.weight}`);
3630
}
3731
else {
38-
if (vertex_1.isWeighted(v)) {
39-
console.log(`${u} -> ${v.node} - ${v.weight}`);
40-
}
41-
else {
42-
console.log(`${u} -> ${v.node}`);
43-
}
32+
console.log(`${u} -> ${v.node} - ${v.weight}`);
4433
}
4534
}
4635
}
@@ -128,12 +117,7 @@ class Graph {
128117
const g = new Graph(true);
129118
for (let [u, vertexList] of this.list) {
130119
for (let v in vertexList) {
131-
if (vertex_1.isWeighted(vertexList[v])) {
132-
g.addVertecesAndEdge(vertexList[v].node, u, vertexList[v].weight);
133-
}
134-
else {
135-
g.addVertecesAndEdge(vertexList[v].node, u);
136-
}
120+
g.addVertecesAndEdge(vertexList[v].node, u, vertexList[v].weight);
137121
}
138122
}
139123
return g;
@@ -186,19 +170,6 @@ class Graph {
186170
if (!this.contains(u) || !this.contains(v))
187171
return false;
188172
let vertexList = this.list.get(u);
189-
// unweighted graph
190-
if (weight === 0) {
191-
vertexList.push({ node: v });
192-
this.list.set(u, vertexList);
193-
if (!this.directed) {
194-
// vertex list of v
195-
let vvl = this.list.get(v);
196-
vvl.push({ node: u });
197-
this.list.set(v, vvl);
198-
}
199-
return this;
200-
}
201-
// weighted graph
202173
vertexList.push({ node: v, weight });
203174
this.list.set(u, vertexList);
204175
if (!this.directed) {
@@ -489,11 +460,14 @@ class Graph {
489460
}
490461
}
491462
}
492-
console.log(`dequeues: ${dequeues},size: ${this.size}, h.size: ${heap.size}`);
463+
// console.log(
464+
// `dequeues: ${dequeues},size: ${this.size}, h.size: ${heap.size}`
465+
// );
493466
return { distances, parents };
494467
};
495468
// Returns the distance from s to each vertex and their parents O(mn)
496469
// negative costs are allowed
470+
// SSSP (Single Source Shortest Problemß)
497471
// detect negative cycles: boolean output (cycle)
498472
// use parents (predecessor pointers) to traverse the cycle
499473
this.bellmanFord = (s) => {
@@ -504,6 +478,7 @@ class Graph {
504478
const parents = new Map();
505479
// to stop earlier
506480
let stop = true;
481+
// i: number of edges allowed
507482
// for i =0, all dist from s to vertex are infinity
508483
for (let [vertex] of this.list) {
509484
if (vertex !== s) {
@@ -542,6 +517,7 @@ class Graph {
542517
};
543518
// Returns the distance from all pair of vertices (u,v) in V
544519
// negative costs are allowed
520+
// APSP (All Pairs Shortest Path)
545521
// use parents (predecessor pointers) to traverse the cycle
546522
// Also returns the last node used in set K
547523
this.floydWarshall = () => {
@@ -585,6 +561,7 @@ class Graph {
585561
}
586562
}
587563
// to expand K to the next vertex of this.list
564+
// O(n3)
588565
for (let k of keys) {
589566
for (let [i] of this.list) {
590567
for (let [j] of this.list) {
@@ -605,7 +582,72 @@ class Graph {
605582
}
606583
return { costs, parents, oldK };
607584
};
608-
// TODO: Johnson's Algorithm?
585+
// Returns the distance from all pair of vertices (u,v) in V
586+
// negative costs are allowed
587+
// Report a negative Cycle (cycle: true)
588+
// APSP (All Pairs Shortest Path)
589+
// use parents (predecessor pointers) to traverse the cycle
590+
// O(mnlog(n))
591+
this.johnson = (s) => {
592+
// map distance between vertex u to v
593+
const dist = new Map();
594+
// map parent of v when u is the start vertex
595+
const par = new Map();
596+
// Form G': equal to G, only add vertex <s>
597+
const newG = new Graph(true);
598+
// O(m)
599+
for (let [u, vertexList] of this.list) {
600+
for (let v of vertexList) {
601+
newG.addVertecesAndEdge(u, v.node, v.weight);
602+
}
603+
}
604+
// Add a new vertex <s> connect to all v in G, with edge cost = 0
605+
// O(n)
606+
newG.addVertex(s);
607+
for (let [v] of this.list) {
608+
if (s !== v)
609+
newG.addEdge(s, v, 0);
610+
}
611+
// runs BF in G' using <s> as start vertex
612+
// BF: O(mn)
613+
const { costs, cycle } = newG.bellmanFord(s);
614+
// check for a negative cycle
615+
if (cycle)
616+
return { cycle: true };
617+
// calcule ce' = ce + pu - pv
618+
// pu and pv are the costs from BF for a pair (u,v) of vertex
619+
// O(m)
620+
for (let [u, vertexList] of this.list) {
621+
for (let v of vertexList) {
622+
const newCost = v.weight + costs.get(u) - costs.get(v.node);
623+
v.weight = newCost;
624+
this.list.set(u, vertexList);
625+
}
626+
}
627+
// run dijkstra for each vertex (using ce')
628+
// ce' is not negative, but dijkstra will retun: d'(u,v)
629+
// d'(u,v) = d(u,v) + pu - pv
630+
// Dijkstra n times: O(nmlog(n))
631+
for (let [u] of this.list) {
632+
const { distances, parents } = this.dijkstra(u);
633+
dist.set(u, distances);
634+
par.set(u, parents);
635+
}
636+
// we nedd to calculate d(u,v)
637+
// d(u,v) = d'(u,v) - pu + pv
638+
// O(n2)
639+
for (let [u] of this.list) {
640+
for (let [v] of this.list) {
641+
if (u !== v) {
642+
const d = dist.get(u).get(v);
643+
const pu = costs.get(u);
644+
const pv = costs.get(v);
645+
dist.get(u).set(v, d - pu + pv);
646+
}
647+
}
648+
}
649+
return { costs: dist, parents: par, cycle };
650+
};
609651
// TODO: USE FIBONACCI HEAP (DECREASE KEY)
610652
// Returns the MST and its cost
611653
this.prim = (s) => {
@@ -849,7 +891,8 @@ Graph.createListAdjWeighted = (file) => {
849891
// File is the adj list of this Graph
850892
// FORMAT: <first vertex u>' '<second vertex v>
851893
// it is a drirected graph, the edge goes from u to v, i.e.: u -> v
852-
Graph.createDirected = (file, w = false) => {
894+
// d to allow duplication
895+
Graph.createDirected = (file, w = false, d = false) => {
853896
// set this graph as directed
854897
const g = new Graph(true);
855898
const data = fs_1.default.readFileSync(file, { encoding: "utf8", flag: "r" });
@@ -862,11 +905,11 @@ Graph.createDirected = (file, w = false) => {
862905
else {
863906
split = line.trim().split(" ");
864907
if (!w) {
865-
g.addVertecesAndEdge(split[0], split[1]);
908+
g.addVertecesAndEdge(split[0], split[1], 0, d);
866909
}
867910
else {
868911
// Avoid duplications!
869-
g.addVertecesAndEdge(split[0], split[1], parseInt(split[2]), false);
912+
g.addVertecesAndEdge(split[0], split[1], parseInt(split[2]), d);
870913
}
871914
line = "";
872915
}

0 commit comments

Comments
 (0)