08-27-周三_17-09-29
This commit is contained in:
27
node_modules/graphlibrary/lib/alg/components.js
generated
vendored
Normal file
27
node_modules/graphlibrary/lib/alg/components.js
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
var _ = require('../lodash')
|
||||
|
||||
module.exports = components
|
||||
|
||||
function components (g) {
|
||||
const visited = {}
|
||||
const cmpts = []
|
||||
let cmpt
|
||||
|
||||
function dfs (v) {
|
||||
if (_.has(visited, v)) return
|
||||
visited[v] = true
|
||||
cmpt.push(v)
|
||||
_.each(g.successors(v), dfs)
|
||||
_.each(g.predecessors(v), dfs)
|
||||
}
|
||||
|
||||
_.each(g.nodes(), function (v) {
|
||||
cmpt = []
|
||||
dfs(v)
|
||||
if (cmpt.length) {
|
||||
cmpts.push(cmpt)
|
||||
}
|
||||
})
|
||||
|
||||
return cmpts
|
||||
}
|
42
node_modules/graphlibrary/lib/alg/dfs.js
generated
vendored
Normal file
42
node_modules/graphlibrary/lib/alg/dfs.js
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
var _ = require('../lodash')
|
||||
|
||||
module.exports = dfs
|
||||
|
||||
/*
|
||||
* A helper that preforms a pre- or post-order traversal on the input graph
|
||||
* and returns the nodes in the order they were visited. If the graph is
|
||||
* undirected then this algorithm will navigate using neighbors. If the graph
|
||||
* is directed then this algorithm will navigate using successors.
|
||||
*
|
||||
* Order must be one of "pre" or "post".
|
||||
*/
|
||||
function dfs (g, vs, order) {
|
||||
if (!_.isArray(vs)) {
|
||||
vs = [vs]
|
||||
}
|
||||
|
||||
var navigation = (g.isDirected() ? g.successors : g.neighbors).bind(g)
|
||||
|
||||
const acc = []
|
||||
const visited = {}
|
||||
_.each(vs, function (v) {
|
||||
if (!g.hasNode(v)) {
|
||||
throw new Error('Graph does not have node: ' + v)
|
||||
}
|
||||
|
||||
doDfs(g, v, order === 'post', visited, navigation, acc)
|
||||
})
|
||||
return acc
|
||||
}
|
||||
|
||||
function doDfs (g, v, postorder, visited, navigation, acc) {
|
||||
if (!_.has(visited, v)) {
|
||||
visited[v] = true
|
||||
|
||||
if (!postorder) { acc.push(v) }
|
||||
_.each(navigation(v), function (w) {
|
||||
doDfs(g, w, postorder, visited, navigation, acc)
|
||||
})
|
||||
if (postorder) { acc.push(v) }
|
||||
}
|
||||
}
|
10
node_modules/graphlibrary/lib/alg/dijkstra-all.js
generated
vendored
Normal file
10
node_modules/graphlibrary/lib/alg/dijkstra-all.js
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
const dijkstra = require('./dijkstra')
|
||||
const _ = require('../lodash')
|
||||
|
||||
module.exports = dijkstraAll
|
||||
|
||||
function dijkstraAll (g, weightFunc, edgeFunc) {
|
||||
return _.transform(g.nodes(), function (acc, v) {
|
||||
acc[v] = dijkstra(g, v, weightFunc, edgeFunc)
|
||||
}, {})
|
||||
}
|
54
node_modules/graphlibrary/lib/alg/dijkstra.js
generated
vendored
Normal file
54
node_modules/graphlibrary/lib/alg/dijkstra.js
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
const _ = require('../lodash')
|
||||
const PriorityQueue = require('../data/priority-queue')
|
||||
|
||||
module.exports = dijkstra
|
||||
|
||||
var DEFAULT_WEIGHT_FUNC = _.constant(1)
|
||||
|
||||
function dijkstra (g, source, weightFn, edgeFn) {
|
||||
return runDijkstra(g, String(source),
|
||||
weightFn || DEFAULT_WEIGHT_FUNC,
|
||||
edgeFn || function (v) { return g.outEdges(v) })
|
||||
}
|
||||
|
||||
function runDijkstra (g, source, weightFn, edgeFn) {
|
||||
const results = {}
|
||||
const pq = new PriorityQueue()
|
||||
let v, vEntry
|
||||
|
||||
var updateNeighbors = function (edge) {
|
||||
const w = edge.v !== v ? edge.v : edge.w
|
||||
const wEntry = results[w]
|
||||
const weight = weightFn(edge)
|
||||
const distance = vEntry.distance + weight
|
||||
|
||||
if (weight < 0) {
|
||||
throw new Error('dijkstra does not allow negative edge weights. ' +
|
||||
'Bad edge: ' + edge + ' Weight: ' + weight)
|
||||
}
|
||||
|
||||
if (distance < wEntry.distance) {
|
||||
wEntry.distance = distance
|
||||
wEntry.predecessor = v
|
||||
pq.decrease(w, distance)
|
||||
}
|
||||
}
|
||||
|
||||
g.nodes().forEach(function (v) {
|
||||
var distance = v === source ? 0 : Number.POSITIVE_INFINITY
|
||||
results[v] = { distance: distance }
|
||||
pq.add(v, distance)
|
||||
})
|
||||
|
||||
while (pq.size() > 0) {
|
||||
v = pq.removeMin()
|
||||
vEntry = results[v]
|
||||
if (vEntry.distance === Number.POSITIVE_INFINITY) {
|
||||
break
|
||||
}
|
||||
|
||||
edgeFn(v).forEach(updateNeighbors)
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
10
node_modules/graphlibrary/lib/alg/find-cycles.js
generated
vendored
Normal file
10
node_modules/graphlibrary/lib/alg/find-cycles.js
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
const _ = require('../lodash')
|
||||
const tarjan = require('./tarjan')
|
||||
|
||||
module.exports = findCycles
|
||||
|
||||
function findCycles (g) {
|
||||
return _.filter(tarjan(g), function (cmpt) {
|
||||
return cmpt.length > 1 || (cmpt.length === 1 && g.hasEdge(cmpt[0], cmpt[0]))
|
||||
})
|
||||
}
|
50
node_modules/graphlibrary/lib/alg/floyd-warshall.js
generated
vendored
Normal file
50
node_modules/graphlibrary/lib/alg/floyd-warshall.js
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
var _ = require('../lodash')
|
||||
|
||||
module.exports = floydWarshall
|
||||
|
||||
var DEFAULT_WEIGHT_FUNC = _.constant(1)
|
||||
|
||||
function floydWarshall (g, weightFn, edgeFn) {
|
||||
return runFloydWarshall(g,
|
||||
weightFn || DEFAULT_WEIGHT_FUNC,
|
||||
edgeFn || function (v) { return g.outEdges(v) })
|
||||
}
|
||||
|
||||
function runFloydWarshall (g, weightFn, edgeFn) {
|
||||
const results = {}
|
||||
const nodes = g.nodes()
|
||||
|
||||
nodes.forEach(function (v) {
|
||||
results[v] = {}
|
||||
results[v][v] = { distance: 0 }
|
||||
nodes.forEach(function (w) {
|
||||
if (v !== w) {
|
||||
results[v][w] = { distance: Number.POSITIVE_INFINITY }
|
||||
}
|
||||
})
|
||||
edgeFn(v).forEach(function (edge) {
|
||||
const w = edge.v === v ? edge.w : edge.v
|
||||
const d = weightFn(edge)
|
||||
results[v][w] = { distance: d, predecessor: v }
|
||||
})
|
||||
})
|
||||
|
||||
nodes.forEach(function (k) {
|
||||
var rowK = results[k]
|
||||
nodes.forEach(function (i) {
|
||||
var rowI = results[i]
|
||||
nodes.forEach(function (j) {
|
||||
var ik = rowI[k]
|
||||
var kj = rowK[j]
|
||||
var ij = rowI[j]
|
||||
var altDistance = ik.distance + kj.distance
|
||||
if (altDistance < ij.distance) {
|
||||
ij.distance = altDistance
|
||||
ij.predecessor = kj.predecessor
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
return results
|
||||
}
|
13
node_modules/graphlibrary/lib/alg/index.js
generated
vendored
Normal file
13
node_modules/graphlibrary/lib/alg/index.js
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
module.exports = {
|
||||
components: require('./components'),
|
||||
dijkstra: require('./dijkstra'),
|
||||
dijkstraAll: require('./dijkstra-all'),
|
||||
findCycles: require('./find-cycles'),
|
||||
floydWarshall: require('./floyd-warshall'),
|
||||
isAcyclic: require('./is-acyclic'),
|
||||
postorder: require('./postorder'),
|
||||
preorder: require('./preorder'),
|
||||
prim: require('./prim'),
|
||||
tarjan: require('./tarjan'),
|
||||
topsort: require('./topsort')
|
||||
}
|
15
node_modules/graphlibrary/lib/alg/is-acyclic.js
generated
vendored
Normal file
15
node_modules/graphlibrary/lib/alg/is-acyclic.js
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
var topsort = require('./topsort')
|
||||
|
||||
module.exports = isAcyclic
|
||||
|
||||
function isAcyclic (g) {
|
||||
try {
|
||||
topsort(g)
|
||||
} catch (e) {
|
||||
if (e instanceof topsort.CycleException) {
|
||||
return false
|
||||
}
|
||||
throw e
|
||||
}
|
||||
return true
|
||||
}
|
7
node_modules/graphlibrary/lib/alg/postorder.js
generated
vendored
Normal file
7
node_modules/graphlibrary/lib/alg/postorder.js
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
var dfs = require('./dfs')
|
||||
|
||||
module.exports = postorder
|
||||
|
||||
function postorder (g, vs) {
|
||||
return dfs(g, vs, 'post')
|
||||
}
|
7
node_modules/graphlibrary/lib/alg/preorder.js
generated
vendored
Normal file
7
node_modules/graphlibrary/lib/alg/preorder.js
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
var dfs = require('./dfs')
|
||||
|
||||
module.exports = preorder
|
||||
|
||||
function preorder (g, vs) {
|
||||
return dfs(g, vs, 'pre')
|
||||
}
|
52
node_modules/graphlibrary/lib/alg/prim.js
generated
vendored
Normal file
52
node_modules/graphlibrary/lib/alg/prim.js
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
const _ = require('../lodash')
|
||||
const Graph = require('../graph')
|
||||
const PriorityQueue = require('../data/priority-queue')
|
||||
|
||||
module.exports = prim
|
||||
|
||||
function prim (g, weightFunc) {
|
||||
const result = new Graph()
|
||||
const parents = {}
|
||||
const pq = new PriorityQueue()
|
||||
let v
|
||||
|
||||
function updateNeighbors (edge) {
|
||||
const w = edge.v === v ? edge.w : edge.v
|
||||
const pri = pq.priority(w)
|
||||
if (pri !== undefined) {
|
||||
var edgeWeight = weightFunc(edge)
|
||||
if (edgeWeight < pri) {
|
||||
parents[w] = v
|
||||
pq.decrease(w, edgeWeight)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (g.nodeCount() === 0) {
|
||||
return result
|
||||
}
|
||||
|
||||
_.each(g.nodes(), function (v) {
|
||||
pq.add(v, Number.POSITIVE_INFINITY)
|
||||
result.setNode(v)
|
||||
})
|
||||
|
||||
// Start from an arbitrary node
|
||||
pq.decrease(g.nodes()[0], 0)
|
||||
|
||||
var init = false
|
||||
while (pq.size() > 0) {
|
||||
v = pq.removeMin()
|
||||
if (_.has(parents, v)) {
|
||||
result.setEdge(v, parents[v])
|
||||
} else if (init) {
|
||||
throw new Error('Input graph is not connected: ' + g)
|
||||
} else {
|
||||
init = true
|
||||
}
|
||||
|
||||
g.nodeEdges(v).forEach(updateNeighbors)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
47
node_modules/graphlibrary/lib/alg/tarjan.js
generated
vendored
Normal file
47
node_modules/graphlibrary/lib/alg/tarjan.js
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
var _ = require('../lodash')
|
||||
|
||||
module.exports = tarjan
|
||||
|
||||
function tarjan (g) {
|
||||
let index = 0
|
||||
const stack = []
|
||||
const visited = {} // node id -> { onStack, lowlink, index }
|
||||
const results = []
|
||||
|
||||
function dfs (v) {
|
||||
var entry = visited[v] = {
|
||||
onStack: true,
|
||||
lowlink: index,
|
||||
index: index++
|
||||
}
|
||||
stack.push(v)
|
||||
|
||||
g.successors(v).forEach(function (w) {
|
||||
if (!_.has(visited, w)) {
|
||||
dfs(w)
|
||||
entry.lowlink = Math.min(entry.lowlink, visited[w].lowlink)
|
||||
} else if (visited[w].onStack) {
|
||||
entry.lowlink = Math.min(entry.lowlink, visited[w].index)
|
||||
}
|
||||
})
|
||||
|
||||
if (entry.lowlink === entry.index) {
|
||||
const cmpt = []
|
||||
let w
|
||||
do {
|
||||
w = stack.pop()
|
||||
visited[w].onStack = false
|
||||
cmpt.push(w)
|
||||
} while (v !== w)
|
||||
results.push(cmpt)
|
||||
}
|
||||
}
|
||||
|
||||
g.nodes().forEach(function (v) {
|
||||
if (!_.has(visited, v)) {
|
||||
dfs(v)
|
||||
}
|
||||
})
|
||||
|
||||
return results
|
||||
}
|
35
node_modules/graphlibrary/lib/alg/topsort.js
generated
vendored
Normal file
35
node_modules/graphlibrary/lib/alg/topsort.js
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
const _ = require('../lodash')
|
||||
|
||||
module.exports = topsort
|
||||
topsort.CycleException = CycleException
|
||||
|
||||
function topsort (g) {
|
||||
const visited = {}
|
||||
const stack = {}
|
||||
const results = []
|
||||
|
||||
function visit (node) {
|
||||
if (_.has(stack, node)) {
|
||||
throw new CycleException()
|
||||
}
|
||||
|
||||
if (!_.has(visited, node)) {
|
||||
stack[node] = true
|
||||
visited[node] = true
|
||||
_.each(g.predecessors(node), visit)
|
||||
delete stack[node]
|
||||
results.push(node)
|
||||
}
|
||||
}
|
||||
|
||||
_.each(g.sinks(), visit)
|
||||
|
||||
if (_.size(visited) !== g.nodeCount()) {
|
||||
throw new CycleException()
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
function CycleException () {}
|
||||
CycleException.prototype = new Error() // must be an instance of Error to pass testing
|
Reference in New Issue
Block a user