UNPKG

js-graph-algorithms

Version:

Package implements data structures and algorithms for processing various types of graphs

1,208 lines (977 loc) 31.5 kB
var jsgraphs = jsgraphs || {}; (function(jss){ jss.less = function(a1, a2, compare) { return compare(a1, a2) < 0; }; jss.exchange = function(a, i, j) { var temp = a[i]; a[i] = a[j]; a[j] = temp; }; var StackNode = function (value) { this.value = value; this.next = null; }; jss.StackNode = StackNode; var Stack = function() { this.N = 0; this.first = null; }; Stack.prototype.push = function (a) { this.first = this._push(this.first, a); }; Stack.prototype._push = function(x, a) { if(x == null) { this.N++; return new jss.StackNode(a); } var oldX = x; this.N++; x = new jss.StackNode(a); x.next = oldX; return x; }; Stack.prototype.pop = function () { if (this.first == null) { return undefined; } var oldFirst = this.first; var item = oldFirst.value; this.first = oldFirst.next; this.N--; return item; }; Stack.prototype.size = function() { return this.N; }; Stack.prototype.isEmpty = function() { return this.N == 0; }; Stack.prototype.peep = function() { if (this.first == null) { return undefined; } return this.first.value; }; Stack.prototype.toArray = function() { var result = []; x = this.first; while (x != null) { result.push(x.value); x = x.next; } return result; }; jss.Stack = Stack; var QueueNode = function(a) { this.value = a; this.next = null; }; jss.QueueNode = QueueNode; var Queue = function() { this.first = null; this.last = null; this.N = 0; }; Queue.prototype.enqueue = function(item) { var oldLast = this.last; this.last = new jss.QueueNode(item); if(oldLast != null){ oldLast.next = this.last; } if (this.first == null) { this.first = this.last; } this.N++; }; Queue.prototype.dequeue = function() { if(this.first == null) { return undefined; } var oldFirst = this.first; var item = oldFirst.value; this.first = oldFirst.next; if(this.first == null) { this.last = null; } this.N--; return item; }; Queue.prototype.size = function() { return this.N; }; Queue.prototype.isEmpty = function() { return this.N == 0; }; Queue.prototype.toArray = function() { var result = []; var x = this.first; while (x != null) { result.push(x.value); x = x.next; } return result; }; jss.Queue = Queue; var MinPQ = function(compare) { this.s = []; this.N = 0; if(!compare) { compare = function(a1, a2) { return a1 - a2; }; } this.compare = compare; }; MinPQ.prototype.enqueue = function(item) { while(this.s.lengh <= this.N+1) { this.s.push(0); } this.s[++this.N] = item; this.swim(this.N); }; MinPQ.prototype.swim = function(k) { while (k > 1){ var parent = Math.floor(k / 2); if(jss.less(this.s[k], this.s[parent], this.compare)){ jss.exchange(this.s, k, parent); k = parent; } else { break; } } }; MinPQ.prototype.delMin = function() { if(this.N == 0) { return undefined; } var item = this.s[1]; jss.exchange(this.s, 1, this.N--); this.sink(1); return item; }; MinPQ.prototype.sink = function(k) { while(k * 2 <= this.N) { var child = 2 * k; if(child < this.N && jss.less(this.s[child+1], this.s[child], this.compare)){ child++; } if(jss.less(this.s[child], this.s[k], this.compare)){ jss.exchange(this.s, child, k); k = child; } else { break; } } }; MinPQ.prototype.size = function(){ return this.N; }; MinPQ.prototype.isEmpty = function() { return this.N == 0; }; jss.MinPQ = MinPQ; var QuickUnion = function(V) { this.id = []; for (var v = 0; v < V; ++v) { this.id.push(v); } }; QuickUnion.prototype.union = function(v, w) { var q = this.root(v); var p = this.root(w); if(p != q) { this.id[p] = q; } }; QuickUnion.prototype.root = function(q) { while(this.id[q] != q) { q = this.id[q]; } return q; }; QuickUnion.prototype.connected = function(v, w) { return this.root(v) == this.root(w); }; jss.QuickUnion = QuickUnion; var IndexMinPQ = function(N, compare) { this.keys = []; this.pq = []; this.qp = []; // positions of key in pq for(var i = 0; i <= N; ++i) { this.keys.push(null); this.pq.push(0); this.qp.push(-1); } this.N = 0; if(!compare) { compare = function(a1, a2) { return a1 - a2; }; } this.compare = compare; }; IndexMinPQ.prototype.insert = function (index, key) { this.keys[index] = key; this.pq[++this.N] = index; this.qp[index] = this.N; this.swim(this.N); }; IndexMinPQ.prototype.decreaseKey = function(index, key) { if(jss.less(key, this.keys[index], this.compare)){ this.keys[index] = key; this.swim(this.qp[index]); } }; IndexMinPQ.prototype.minKey = function() { return this.keys[this.pq[1]]; }; IndexMinPQ.prototype.min = function() { return this.pq[1]; }; IndexMinPQ.prototype.delMin = function() { var key = this.pq[1]; jss.exchange(this.pq, 1, this.N); this.qp[this.pq[1]] = 1; this.qp[this.pq[this.N]] = -1; this.keys[this.pq[this.N]] = null; this.N--; this.sink(1); return key; }; IndexMinPQ.prototype.swim = function (k) { while( k > 1) { var parent = Math.floor(k / 2); if(jss.less(this.keys[this.pq[k]], this.keys[this.pq[parent]], this.compare)){ jss.exchange(this.pq, k, parent); this.qp[this.pq[k]] = k; this.qp[this.pq[parent]] = parent; k = parent; } else { break; } } }; IndexMinPQ.prototype.sink = function (k) { while(2 * k <= this.N) { var child = k * 2; if(child < this.N && jss.less(this.keys[this.pq[child+1]], this.keys[this.pq[child]], this.compare)){ child++; } if(jss.less(this.keys[this.pq[child]], this.keys[this.pq[k]], this.compare)) { jss.exchange(this.pq, k, child); this.qp[this.pq[k]] = k; this.qp[this.pq[child]] = child; k = child; } else { break; } } }; IndexMinPQ.prototype.containsIndex = function (index) { return this.qp[index] != -1; }; IndexMinPQ.prototype.isEmpty = function() { return this.N == 0; }; IndexMinPQ.prototype.size = function() { return this.N; } jss.IndexMinPQ = IndexMinPQ; var Graph = function (V) { this.V = V; this.adjList = []; this.nodeInfo = []; this.edges = {}; for (var i = 0; i < V; ++i) { this.adjList.push([]); this.nodeInfo.push({}); } }; Graph.prototype.addEdge = function(v, w){ this.adjList[v].push(w); this.adjList[w].push(v); var edge_id = v + '_' + w; if(v > w) { edge_id = w + '_' + v; } this.edges[edge_id] = new jss.Edge(v, w, 0); }; Graph.prototype.adj = function(v) { return this.adjList[v]; }; Graph.prototype.node = function(v) { return this.nodeInfo[v]; }; Graph.prototype.edge = function(v, w) { var edge_id = v + '_' + w; if(v > w) { edge_id = w + '_' + v; } if (edge_id in this.edges) { return this.edges[edge_id]; } return null; }; jss.Graph = Graph; var DiGraph = function(V) { this.V = V; this.adjList = []; this.nodeInfo = []; this.edges = {}; for (var v = 0; v < V; ++v){ this.adjList.push([]); this.nodeInfo.push({}); } }; DiGraph.prototype.addEdge = function(v, w){ this.adjList[v].push(w); var edge_id = v + '_' + w; this.edges[edge_id] = new jss.Edge(v, w, 0); }; DiGraph.prototype.edge = function(v, w) { var edge_id = v + '_' + w; if(edge_id in this.edges) { return this.edges[edge_id]; } else { return null; } }; DiGraph.prototype.adj = function(v) { return this.adjList[v]; }; DiGraph.prototype.node = function(v) { return this.nodeInfo[v]; }; DiGraph.prototype.reverse = function(){ var g = new DiGraph(this.V); for (var v = 0; v < this.V; ++v) { var adj_v = this.adjList[v]; for (var i = 0; i < adj_v.length; ++i){ var w = adj_v[i]; g.addEdge(w, v); } } return g; }; jss.DiGraph = DiGraph; var Edge = function(v, w, weight) { this.v = v; this.w = w; this.weight = weight; }; Edge.prototype.either = function() { return this.v; }; Edge.prototype.other = function(x) { return x == this.v ? this.w : this.v; }; Edge.prototype.from = function() { return this.v; }; Edge.prototype.to = function() { return this.w; }; jss.Edge = Edge; var WeightedGraph = function(V) { this.V = V; this.adjList = []; this.nodeInfo = []; for ( var v = 0; v < V; ++v) { this.adjList.push([]); this.nodeInfo.push({}); } }; WeightedGraph.prototype.adj = function(v) { return this.adjList[v]; }; WeightedGraph.prototype.edge = function(v, w) { var adj_v = this.adjList[v]; for(var i=0; i < adj_v.length; ++i) { var x = adj_v[i].other(v); if(x == w) { return adj_v[i]; } } return null; }; WeightedGraph.prototype.node = function(v) { return this.nodeInfo[v]; }; WeightedGraph.prototype.addEdge = function(e) { var v = e.either(); var w = e.other(v); this.adjList[v].push(e); this.adjList[w].push(e); }; jss.WeightedGraph = WeightedGraph; var WeightedDiGraph = function(V) { WeightedGraph.call(this, V); }; WeightedDiGraph.prototype = Object.create(jss.WeightedGraph.prototype); WeightedDiGraph.prototype.addEdge = function(e) { var v = e.from(); this.adjList[v].push(e); }; WeightedDiGraph.prototype.edge = function(v, w) { var adj_v = this.adjList[v]; for(var i=0; i < adj_v.length; ++i) { var x = adj_v[i].other(v); if(x == w) { return adj_v[i]; } } return null; }; WeightedDiGraph.prototype.toDiGraph = function() { var g = new jss.DiGraph(this.V); for(var v = 0; v < this.V; ++v) { var adj_v = this.adjList[v]; for (var i =0; i < adj_v.length; ++i) { var e = adj_v[i]; var w = e.other(v); g.addEdge(v, w); } } return g; }; jss.WeightedDiGraph = WeightedDiGraph; var FlowEdge = function(v, w, capacity) { this.v = v; this.w = w; this.capacity = capacity; this.flow = 0; }; FlowEdge.prototype.residualCapacityTo = function (x) { if(x == this.v) { return this.flow; } else { return this.capacity - this.flow; } }; FlowEdge.prototype.addResidualFlowTo = function (x, deltaFlow) { if(x == this.v) { this.flow -= deltaFlow; } else if(x == this.w) { this.flow += deltaFlow; } }; FlowEdge.prototype.from = function() { return this.v; }; FlowEdge.prototype.to = function() { return this.w; }; FlowEdge.prototype.other = function(x) { return x == this.v ? this.w : this.v; } jss.FlowEdge = FlowEdge; var FlowNetwork = function(V) { this.V = V; this.adjList = []; this.nodeInfo = []; for(var v = 0; v < V; ++v) { this.adjList.push([]); this.nodeInfo.push({}); } }; FlowNetwork.prototype.node = function(v) { return this.nodeInfo[v]; }; FlowNetwork.prototype.edge = function(v, w) { var adj_v = this.adjList[v]; for(var i=0; i < adj_v.length; ++i) { var x = adj_v[i].other(v); if(x == w) { return adj_v[i]; } } return null; }; FlowNetwork.prototype.addEdge = function(e) { var v = e.from(); this.adjList[v].push(e); var w = e.other(v); this.adjList[w].push(e); }; FlowNetwork.prototype.adj = function(v) { return this.adjList[v]; }; jss.FlowNetwork = FlowNetwork; var DepthFirstSearch = function(G, s) { this.s = s; var V = G.V; this.marked = []; this.edgeTo = []; for (var v = 0; v < V; ++v) { this.marked.push(false); this.edgeTo.push(-1); } this.dfs(G, s); }; DepthFirstSearch.prototype.dfs = function (G, v) { this.marked[v] = true; var adj_v = G.adj(v); for (var i = 0; i < adj_v.length; ++i){ var w = adj_v[i]; if (!this.marked[w]){ this.edgeTo[w] = v; this.dfs(G, w); } } }; DepthFirstSearch.prototype.hasPathTo = function(v) { return this.marked[v]; }; DepthFirstSearch.prototype.pathTo = function(v) { var path = new jss.Stack(); if(v == this.s) return [v]; for(var x = v; x != this.s; x = this.edgeTo[x]) { path.push(x); } path.push(this.s); return path.toArray(); }; jss.DepthFirstSearch = DepthFirstSearch; var BreadthFirstSearch = function(G, s) { var V = G.V; this.s = s; var queue = new jss.Queue(); queue.enqueue(s); this.marked = []; this.edgeTo = []; for(var v = 0; v < V; ++v) { this.marked.push(false); this.edgeTo.push(-1); } while (!queue.isEmpty()) { var v = queue.dequeue(); this.marked[v] = true; var adj_v = G.adj(v); for (var i = 0; i < adj_v.length; ++i) { var w = adj_v[i]; if(!this.marked[w]){ this.edgeTo[w] = v; queue.enqueue(w); } } } }; BreadthFirstSearch.prototype.hasPathTo = function(v) { return this.marked[v]; }; BreadthFirstSearch.prototype.pathTo = function(v) { var path = new jss.Stack(); if(v == this.s) return [v]; for(var x = v; x != this.s; x = this.edgeTo[x]) { path.push(x); } path.push(this.s); return path.toArray(); }; jss.BreadthFirstSearch = BreadthFirstSearch; var ConnectedComponents = function(G) { this.count = 0; var V = G.V; this.marked = []; this.id = []; for (var v = 0; v < V; ++v) { this.marked.push(false); this.id.push(-1); } for (var v = 0; v < V; ++v) { if(!this.marked[v]){ this.dfs(G, v); this.count++; } } }; ConnectedComponents.prototype.dfs = function(G, v) { this.marked[v] = true; this.id[v] = this.count; var adj_v = G.adj(v); for(var i = 0; i < adj_v.length; ++i){ var w = adj_v[i]; if(!this.marked[w]){ this.dfs(G, w); } } }; ConnectedComponents.prototype.componentId = function(v) { return this.id[v]; }; ConnectedComponents.prototype.componentCount = function(){ return this.count; }; jss.ConnectedComponents = ConnectedComponents; var TopologicalSort = function(G) { this.postOrder = new jss.Stack(); this.marked = []; var V = G.V; for (var v = 0; v < V; ++v) { this.marked.push(false); } for (var v = 0; v < V; ++v) { if(!this.marked[v]) { this.dfs(G, v); } } }; TopologicalSort.prototype.dfs = function(G, v) { this.marked[v] = true; var adj_v = G.adj(v); for (var i = 0; i < adj_v.length; ++i) { var w = adj_v[i]; if(!this.marked[w]){ this.dfs(G, w); } } this.postOrder.push(v); }; TopologicalSort.prototype.order = function() { return this.postOrder.toArray(); }; jss.TopologicalSort = TopologicalSort; var StronglyConnectedComponents = function(G) { var V = G.V; this.count = 0; this.marked = []; this.id = []; for(var v = 0; v < V; ++v) { this.marked.push(false); this.id.push(-1); } var order = new jss.TopologicalSort(G.reverse()).order(); for( var i = 0; i < order.length; ++i) { var v = order[i]; if(!this.marked[v]){ this.dfs(G, v); this.count++; } } }; StronglyConnectedComponents.prototype.dfs = function (G, v) { this.marked[v] = true; this.id[v] = this.count; var adj_v = G.adj(v); for (var i = 0; i < adj_v.length; ++i){ var w = adj_v[i]; if(!this.marked[w]){ this.dfs(G, w); } } }; StronglyConnectedComponents.prototype.componentId = function(v) { return this.id[v]; }; StronglyConnectedComponents.prototype.componentCount = function(){ return this.count; }; jss.StronglyConnectedComponents = StronglyConnectedComponents; var KruskalMST = function(G) { var V = G.V; var pq = new jss.MinPQ(function(e1, e2){ return e1.weight - e2.weight; }); for(var v = 0; v < G.V; ++v){ var adj_v = G.adj(v); for (var i = 0; i < adj_v.length; ++i) { var e = adj_v[i]; if(e.either() != v) { continue; } pq.enqueue(e); } } this.mst = []; var uf = new jss.QuickUnion(V); while (!pq.isEmpty() && this.mst.length < V-1) { var e = pq.delMin(); var v = e.either(); var w = e.other(v); if(!uf.connected(v, w)){ uf.union(v, w); this.mst.push(e); } } }; jss.KruskalMST = KruskalMST; var LazyPrimMST = function(G) { var V = G.V; this.marked = []; for( var v = 0; v < V; ++v) { this.marked.push(false); } this.pq = new jss.MinPQ(function(e1, e2){ return e1.weight - e2.weight; }); this.mst = []; this.visit(G, 0); while(!this.pq.isEmpty() && this.mst.length < V-1) { var e = this.pq.delMin(); var v = e.either(); var w = e.other(v); if(this.marked[v] && this.marked[w]) continue; this.mst.push(e); if(!this.marked[v]) this.visit(G, v); if(!this.marked[w]) this.visit(G, w); } }; LazyPrimMST.prototype.visit = function(G, v) { this.marked[v] = true; var adj_v = G.adj(v); for (var i = 0; i < adj_v.length; ++i) { var e = adj_v[i]; if(!this.marked[e.other(v)]){ this.pq.enqueue(e); } } }; jss.LazyPrimMST = LazyPrimMST; var EagerPrimMST = function(G) { var V = G.V; this.pq = new jss.IndexMinPQ(V, function(e1, e2) { return e1.weight - e2.weight; }); this.marked = []; for(var v = 0; v < V; ++v) { this.marked.push(false); } this.mst = []; this.visit(G, 0); while(!this.pq.isEmpty()) { var e = this.pq.minKey(); var w = this.pq.delMin(); this.mst.push(e); if(!this.marked[w]){ this.visit(G, w); } } }; EagerPrimMST.prototype.visit = function(G, v) { this.marked[v] = true; var adj_v = G.adj(v); for(var i = 0; i < adj_v.length; ++i) { var e = adj_v[i]; var w = e.other(v); if(this.marked[w]) continue; if(this.pq.containsIndex(w)){ this.pq.decreaseKey(w, e); } else { this.pq.insert(w, e); } } }; jss.EagerPrimMST = EagerPrimMST; var Dijkstra = function(G, s) { var V = G.V; this.s = s; this.marked = []; this.edgeTo = []; this.cost = []; this.pq = new jss.IndexMinPQ(V, function(cost1, cost2){ return cost1, cost2; }); for(var v =0; v < V; ++v){ this.marked.push(false); this.edgeTo.push(null); this.cost.push(Number.MAX_VALUE); } this.cost[s] = 0; this.pq.insert(s, this.cost[s]); while(!this.pq.isEmpty()) { var v = this.pq.delMin(); this.marked[v] = true; var adj_v = G.adj(v); for(var i = 0; i < adj_v.length; ++i) { var e = adj_v[i]; this.relax(e); } } }; Dijkstra.prototype.relax = function(e) { var v = e.from(); var w = e.to(); if(this.cost[w] > this.cost[v] + e.weight) { this.cost[w] = this.cost[v] + e.weight; this.edgeTo[w] = e; if(this.pq.containsIndex(w)){ this.pq.decreaseKey(w, this.cost[w]); } else { this.pq.insert(w, this.cost[w]); } } }; Dijkstra.prototype.hasPathTo = function(v) { return this.marked[v]; }; Dijkstra.prototype.pathTo = function(v) { var path = new jss.Stack(); for(var x = v; x != this.s; x = this.edgeTo[x].other(x)) { path.push(this.edgeTo[x]); } return path.toArray(); }; Dijkstra.prototype.distanceTo = function(v) { return this.cost[v]; }; jss.Dijkstra = Dijkstra; var BellmanFord = function(G, s) { var V = G.V; this.s = s; this.marked = []; this.edgeTo = []; this.cost = []; for(var v =0; v < V; ++v){ this.marked.push(false); this.edgeTo.push(null); this.cost.push(Number.MAX_VALUE); } this.cost[s] = 0; this.marked[s] = true; for(var j = 0; j < V; ++j) { for(var v = 0; v < V; ++v){ var adj_v = G.adj(v); for(var i = 0; i < adj_v.length; ++i) { var e = adj_v[i]; this.relax(e); } } } }; BellmanFord.prototype.relax = function(e) { var v = e.from(); var w = e.to(); if(this.cost[w] > this.cost[v] + e.weight) { this.cost[w] = this.cost[v] + e.weight; this.marked[w] = true; this.edgeTo[w] = e; } }; BellmanFord.prototype.hasPathTo = function(v) { return this.marked[v]; }; BellmanFord.prototype.pathTo = function(v) { var path = new jss.Stack(); for(var x = v; x != this.s; x = this.edgeTo[x].other(x)) { path.push(this.edgeTo[x]); } return path.toArray(); }; BellmanFord.prototype.distanceTo = function(v) { return this.cost[v]; }; jss.BellmanFord = BellmanFord; var TopologicalSortShortestPaths = function(G, s) { var V = G.V; this.s = s; this.marked = []; this.edgeTo = []; this.cost = []; for(var v =0; v < V; ++v){ this.marked.push(false); this.edgeTo.push(null); this.cost.push(Number.MAX_VALUE); } this.cost[s] = 0; this.marked[s] = true; var order = new jss.TopologicalSort(G.toDiGraph()).order(); for(var j = 0; j < order.length; ++j){ var v = order[j]; var adj_v = G.adj(v); for(var i = 0; i < adj_v.length; ++i) { var e = adj_v[i]; this.relax(e); } } }; TopologicalSortShortestPaths.prototype.relax = function(e) { var v = e.from(); var w = e.to(); if(this.cost[w] > this.cost[v] + e.weight) { this.cost[w] = this.cost[v] + e.weight; this.marked[w] = true; this.edgeTo[w] = e; } }; TopologicalSortShortestPaths.prototype.hasPathTo = function(v) { return this.marked[v]; }; TopologicalSortShortestPaths.prototype.pathTo = function(v) { var path = new jss.Stack(); for(var x = v; x != this.s; x = this.edgeTo[x].other(x)) { path.push(this.edgeTo[x]); } return path.toArray(); }; TopologicalSortShortestPaths.prototype.distanceTo = function(v) { return this.cost[v]; }; jss.TopologicalSortShortestPaths = TopologicalSortShortestPaths; var FordFulkerson = function(G, s, t) { this.value = 0; var V = G.V; var bottle = Number.MAX_VALUE; this.marked = null; this.edgeTo = null; this.s = s; this.t = t; while(this.hasAugmentedPath(G)){ for(var x = this.t; x != this.s; x = this.edgeTo[x].other(x)) { bottle = Math.min(bottle, this.edgeTo[x].residualCapacityTo(x)); } for(var x = this.t; x != this.s; x = this.edgeTo[x].other(x)) { this.edgeTo[x].addResidualFlowTo(x, bottle); } this.value += bottle; } }; FordFulkerson.prototype.hasAugmentedPath = function(G) { var V = G.V; this.marked = []; this.edgeTo = []; for(var v = 0; v < V; ++v) { this.marked.push(false); this.edgeTo.push(null); } var queue = new jss.Queue(); queue.enqueue(this.s); this.marked[this.s] = true; while(!queue.isEmpty()){ var v = queue.dequeue(); var adj_v = G.adj(v); for (var i = 0; i < adj_v.length; ++i) { var e = adj_v[i]; var w = e.other(v); if(!this.marked[w] && e.residualCapacityTo(w) > 0){ this.edgeTo[w] = e; this.marked[w] = true; if(w == this.t){ return true; } queue.enqueue(w); } } } return false; }; FordFulkerson.prototype.minCut = function(G) { var cuts = []; var V = G.V; for(var v = 0; v < V; ++v){ var adj_v = G.adj(v); for(var i = 0; i < adj_v.length; ++i) { var e = adj_v[i]; if(e.from() == v && e.residualCapacityTo(e.other(v)) == 0) { cuts.push(e); } } } return cuts; }; jss.FordFulkerson = FordFulkerson; })(jsgraphs); var module = module || {}; if(module) { module.exports = jsgraphs; }