From 86a27ee94fd1e862b0677643d3852a9c7e57ce27 Mon Sep 17 00:00:00 2001 From: Dspade0 Date: Mon, 13 Mar 2017 18:26:09 +0200 Subject: [PATCH 01/10] added eslint configuration --- .eslintrc.yml | 173 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 .eslintrc.yml diff --git a/.eslintrc.yml b/.eslintrc.yml new file mode 100644 index 0000000..de3adce --- /dev/null +++ b/.eslintrc.yml @@ -0,0 +1,173 @@ +env: + es6: true + node: true +extends: 'eslint:recommended' +globals: + api: false +rules: + indent: + - error + - 2 + - SwitchCase: 1 + VariableDeclarator: + var: 2 + let: 2 + const: 3 + MemberExpression: 1 + linebreak-style: + - error + - unix + quotes: + - error + - single + semi: + - error + - always + eqeqeq: + - error + - always + no-loop-func: + - error + strict: + - error + - global + block-spacing: + - error + - always + brace-style: + - error + - 1tbs + - allowSingleLine: true + camelcase: + - error + comma-style: + - error + - last + comma-spacing: + - error + - before: false + after: true + eol-last: + - error + func-call-spacing: + - error + - never + key-spacing: + - error + - beforeColon: false + afterColon: true + mode: minimum + keyword-spacing: + - error + - before: true + after: true + overrides: + function: + after: false + max-len: + - error + - code: 80 + ignoreUrls: true + max-nested-callbacks: + - error + - max: 7 + new-cap: + - error + - newIsCap: true + capIsNew: true + properties: true + new-parens: + - error + no-lonely-if: + - error + no-trailing-spaces: + - error + no-unneeded-ternary: + - error + no-whitespace-before-property: + - error + object-curly-spacing: + - error + - always + operator-assignment: + - error + - always + operator-linebreak: + - error + - after + semi-spacing: + - error + - before: false + after: true + space-before-blocks: + - error + - always + space-before-function-paren: + - error + - never + space-in-parens: + - error + - never + space-infix-ops: + - error + space-unary-ops: + - error + - words: true + nonwords: false + overrides: + typeof: false + no-unreachable: + - error + no-global-assign: + - error + no-self-compare: + - error + no-unmodified-loop-condition: + - error + no-constant-condition: + - error + - checkLoops: false + no-console: + - off + no-useless-concat: + - error + no-useless-escape: + - error + no-shadow-restricted-names: + - error + no-use-before-define: + - error + - functions: false + arrow-body-style: + - error + - as-needed + arrow-spacing: + - error + no-confusing-arrow: + - error + - allowParens: true + no-useless-computed-key: + - error + no-useless-rename: + - error + no-var: + - error + object-shorthand: + - error + - always + prefer-arrow-callback: + - error + prefer-const: + - error + prefer-numeric-literals: + - error + prefer-rest-params: + - error + prefer-spread: + - error + rest-spread-spacing: + - error + - never + template-curly-spacing: + - error + - never From 66ba948ce1ade3266eab3ffee148b550bdd720ef Mon Sep 17 00:00:00 2001 From: Dspade0 Date: Mon, 13 Mar 2017 19:50:52 +0200 Subject: [PATCH 02/10] implemented primitive methods --- JavaScript/1-directedGraph.js | 40 +++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 JavaScript/1-directedGraph.js diff --git a/JavaScript/1-directedGraph.js b/JavaScript/1-directedGraph.js new file mode 100644 index 0000000..65d55d5 --- /dev/null +++ b/JavaScript/1-directedGraph.js @@ -0,0 +1,40 @@ +'use strict'; + +class DirectedGraph { + constructor(vertexN) { + this._adjacency = []; // _adjacency[v] = adjacency array for vertex v + this._indegree = []; // _indegree[v] = indegree of vertex v + this._weight = []; // _weight[v][w] = weight of the edge (v; w) + if (vertexN === undefined) return this; + let i; + for (i = 0; i < vertexN; ++i) { + this.addVertex(); + } + return this; + } + addVertex() { + this._adjacency.push([]); + this._weight.push([]); + const vertexIndex = this._adjacency.length - 1; + this._indegree[vertexIndex] = 0; + return this; + } + hasVertex(v) { + if (v < 0 || v >= this.size) { + return false; + } + return true; + } + get size() { + return this._adjacency.length; + } + connect(v1, v2, weight) { + if (!this.hasVertex(v1) || !this.hasVertex(v2)) { + return false; + } + this._adjacency[v1].push(v2); + this._weight[v1][v2] = weight; + ++this._indegree[v2]; + return true; + } +} From 7b1d85d680c1a67de3f69d04f872aad6429096e6 Mon Sep 17 00:00:00 2001 From: Dspade0 Date: Mon, 13 Mar 2017 22:24:48 +0200 Subject: [PATCH 03/10] implemented disconnect method --- JavaScript/1-directedGraph.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/JavaScript/1-directedGraph.js b/JavaScript/1-directedGraph.js index 65d55d5..23b3747 100644 --- a/JavaScript/1-directedGraph.js +++ b/JavaScript/1-directedGraph.js @@ -37,4 +37,14 @@ class DirectedGraph { ++this._indegree[v2]; return true; } + disconnect(v1, v2) { + if (!this.hasVertex(v1) || !this.hasVertex(v2)) { + return false; + } + const vertexIndex = this._adjacency[v1].indexOf(v2); + if (vertexIndex === -1) return false; + this._adjacency[v1].splice(vertexIndex, 1); + this._weight[v1][v2] = undefined; + --this._indegree[v2]; + } } From 93f50b62d93896f3966ab6d8856b3c6a7858fb99 Mon Sep 17 00:00:00 2001 From: Dspade0 Date: Mon, 13 Mar 2017 22:41:24 +0200 Subject: [PATCH 04/10] implemented isConnect method --- JavaScript/1-directedGraph.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/JavaScript/1-directedGraph.js b/JavaScript/1-directedGraph.js index 23b3747..aaec662 100644 --- a/JavaScript/1-directedGraph.js +++ b/JavaScript/1-directedGraph.js @@ -42,9 +42,18 @@ class DirectedGraph { return false; } const vertexIndex = this._adjacency[v1].indexOf(v2); - if (vertexIndex === -1) return false; + if (vertexIndex < 0) return false; this._adjacency[v1].splice(vertexIndex, 1); this._weight[v1][v2] = undefined; --this._indegree[v2]; + return true; + } + isConnected(v1, v2) { + if (!this.hasVertex(v1) || !this.hasVertex(v2)) { + return false; + } + const vertexIndex = this._adjacency[v1].indexOf(v2); + if (vertexIndex < 0) return false; + return true; } } From 99ca51a419564918b4a92647de6cc2629e40380c Mon Sep 17 00:00:00 2001 From: Dspade0 Date: Mon, 13 Mar 2017 23:19:36 +0200 Subject: [PATCH 05/10] implemented getWeight and transpose methods --- JavaScript/1-directedGraph.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/JavaScript/1-directedGraph.js b/JavaScript/1-directedGraph.js index aaec662..09c93bc 100644 --- a/JavaScript/1-directedGraph.js +++ b/JavaScript/1-directedGraph.js @@ -56,4 +56,19 @@ class DirectedGraph { if (vertexIndex < 0) return false; return true; } + getWeight(v1, v2) { + return this._weight[v1][v2]; + } + transpose() { + const size = this.size; + let transposedGraph = new DirectedGraph(size); + let v, w, weight; + for (v = 0; v < size; ++v) { + for (w of this._adjacency[v]) { + weight = this.getWeight(v, w); + transposedGraph.connect(w, v, weight); + } + } + return transposedGraph; + } } From 71959c539dc9be584cab863b1e1860353bcfdec1 Mon Sep 17 00:00:00 2001 From: Dspade0 Date: Tue, 14 Mar 2017 02:59:36 +0200 Subject: [PATCH 06/10] implemented minimumDistance method with Belman-Ford algorithm --- JavaScript/1-directedGraph.js | 40 +++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/JavaScript/1-directedGraph.js b/JavaScript/1-directedGraph.js index 09c93bc..d186f29 100644 --- a/JavaScript/1-directedGraph.js +++ b/JavaScript/1-directedGraph.js @@ -71,4 +71,44 @@ class DirectedGraph { } return transposedGraph; } + /** + * Computes shortest paths from a single source vertex + * to all of the other vertices (Bellman-Ford inplementation). + * + * @param from = the vertex + * @return distanceArr[v] = minimum distance to v + * parentArr[v] = parent vertex for v in the shortest path + */ + minimunDistance(from) { + if (!this.hasVertex(from)) { + return null; + } + let distance = new Array(this.size); + let parent = new Array(this.size); + let i; + for (i = 0; i < this.size; ++i) { + distance[i] = Infinity; + parent[i] = -1; + } + distance[from] = 0; + for (i = 0; i < this.size - 1; ++i) { + this._adjacency.forEach((adj, v) => { // for each vertex in the graph + adj.forEach(w => { // for each adjacent vertex w to v + if (distance[w] > distance[v] + this.getWeight(v, w)) { + distance[w] = distance[v] + this.getWeight(v, w); + parent[w] = v; + } + }); + }); + } + // if any distance[i] changes, the graph has negative cycles + this._adjacency.forEach((adj, v) => { + adj.forEach(w => { + if (distance[w] > distance[v] + this.getWeight(v, w)) { + return null; + } + }); + }); + return { distanceArr: distance, parentArr: parent }; + } } From 0a21f21b0d1a20fd1a847fac42892fad69f18cf6 Mon Sep 17 00:00:00 2001 From: Dspade0 Date: Tue, 14 Mar 2017 03:02:39 +0200 Subject: [PATCH 07/10] added an example of using DirectedGraph --- JavaScript/1-directedGraph.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/JavaScript/1-directedGraph.js b/JavaScript/1-directedGraph.js index d186f29..d27dacc 100644 --- a/JavaScript/1-directedGraph.js +++ b/JavaScript/1-directedGraph.js @@ -112,3 +112,27 @@ class DirectedGraph { return { distanceArr: distance, parentArr: parent }; } } + +const myGraph = new DirectedGraph(4); +myGraph.connect(0, 1, 2); +myGraph.connect(0, 2, 3); +myGraph.connect(1, 2, -2); +myGraph.connect(1, 3, 2); +myGraph.connect(2, 3, 3); + +const checkVertex = 0; +const checkEdge = [2, 3]; +if (myGraph.hasVertex(checkVertex)) { + console.log('I have vertex ' + checkVertex); +} else { + console.log('I do not have a vertex ' + checkVertex + ' :('); +} +if (myGraph.isConnected(...checkEdge)) { + console.log(checkEdge[0] + ' is connected with ' + checkEdge[1]); + console.log('It has weight ' + myGraph.getWeight(...checkEdge)); +} +console.log('Lets find the shortest paths for checkVertex!'); +console.time('Belman-Ford'); +const result = myGraph.minimunDistance(checkVertex); +console.timeEnd('Belman-Ford'); +console.dir(result); From 4b5fe094fe5843e2a1410b9ddc969254edf48943 Mon Sep 17 00:00:00 2001 From: Dspade0 Date: Wed, 15 Mar 2017 13:36:44 +0200 Subject: [PATCH 08/10] use const instead of let --- JavaScript/1-directedGraph.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/JavaScript/1-directedGraph.js b/JavaScript/1-directedGraph.js index d27dacc..5ee3bbe 100644 --- a/JavaScript/1-directedGraph.js +++ b/JavaScript/1-directedGraph.js @@ -61,7 +61,7 @@ class DirectedGraph { } transpose() { const size = this.size; - let transposedGraph = new DirectedGraph(size); + const transposedGraph = new DirectedGraph(size); let v, w, weight; for (v = 0; v < size; ++v) { for (w of this._adjacency[v]) { @@ -83,8 +83,8 @@ class DirectedGraph { if (!this.hasVertex(from)) { return null; } - let distance = new Array(this.size); - let parent = new Array(this.size); + const distance = new Array(this.size); + const parent = new Array(this.size); let i; for (i = 0; i < this.size; ++i) { distance[i] = Infinity; From 2ee6fab8f94e489404f57c8a18676a3a4b3955b2 Mon Sep 17 00:00:00 2001 From: Dspade0 Date: Wed, 15 Mar 2017 21:41:16 +0200 Subject: [PATCH 09/10] used loops 'for' instead of forEach to correctly return null --- JavaScript/1-directedGraph.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/JavaScript/1-directedGraph.js b/JavaScript/1-directedGraph.js index 5ee3bbe..9126d84 100644 --- a/JavaScript/1-directedGraph.js +++ b/JavaScript/1-directedGraph.js @@ -79,7 +79,7 @@ class DirectedGraph { * @return distanceArr[v] = minimum distance to v * parentArr[v] = parent vertex for v in the shortest path */ - minimunDistance(from) { + minimumDistance(from) { if (!this.hasVertex(from)) { return null; } @@ -92,23 +92,23 @@ class DirectedGraph { } distance[from] = 0; for (i = 0; i < this.size - 1; ++i) { - this._adjacency.forEach((adj, v) => { // for each vertex in the graph - adj.forEach(w => { // for each adjacent vertex w to v + for (let v in this._adjacency) { // for each vertex v + for (let w of this._adjacency[v]) { // for each incident edge for v if (distance[w] > distance[v] + this.getWeight(v, w)) { distance[w] = distance[v] + this.getWeight(v, w); parent[w] = v; } - }); - }); + } + } } // if any distance[i] changes, the graph has negative cycles - this._adjacency.forEach((adj, v) => { - adj.forEach(w => { + for (let v in this._adjacency) { + for (let w of this._adjacency[v]) { if (distance[w] > distance[v] + this.getWeight(v, w)) { return null; } - }); - }); + } + } return { distanceArr: distance, parentArr: parent }; } } @@ -133,6 +133,6 @@ if (myGraph.isConnected(...checkEdge)) { } console.log('Lets find the shortest paths for checkVertex!'); console.time('Belman-Ford'); -const result = myGraph.minimunDistance(checkVertex); +const result = myGraph.minimumDistance(checkVertex); console.timeEnd('Belman-Ford'); console.dir(result); From a5a97827452ea35b082fe04602ca9113a823d187 Mon Sep 17 00:00:00 2001 From: Dspade0 Date: Wed, 15 Mar 2017 23:18:51 +0200 Subject: [PATCH 10/10] added toposort method --- JavaScript/1-directedGraph.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/JavaScript/1-directedGraph.js b/JavaScript/1-directedGraph.js index 9126d84..ff4245f 100644 --- a/JavaScript/1-directedGraph.js +++ b/JavaScript/1-directedGraph.js @@ -111,6 +111,28 @@ class DirectedGraph { } return { distanceArr: distance, parentArr: parent }; } + toposort() { + const grey = 1, + black = 2, + sorted = new Array(), + marked = new Array(this.size); + const dfs = (v) => { + if (marked[v] === grey) return 0; + if (marked[v] === black) return 1; + marked[v] = grey; + for (let w of this._adjacency[v]) { + if (!dfs(w)) return undefined; + } + marked[v] = black; + sorted.unshift(v); + return marked[v]; + }; + for (let v in this._adjacency) { + if (marked[v]) continue; + if (!dfs(v)) return null; + } + return sorted; + } } const myGraph = new DirectedGraph(4); @@ -136,3 +158,5 @@ console.time('Belman-Ford'); const result = myGraph.minimumDistance(checkVertex); console.timeEnd('Belman-Ford'); console.dir(result); + +console.log('Toposort test: ' + myGraph.toposort());