function deleteMin(pq){
pq.sort(lengthSort)
return pq.shift()
}
//function lengthSort(a,b){return a[2]<b[2]?-1:1}
function lengthSort(a,b){return a[2]-b[2]}
/*因为dijkstra算法不能出现有向环,这个方法判断是否有环,有就删除遍历时找到的最后一条边
最终的检测方法只能检测有环非负图,因为如果dijkstra里有负边会导致start不到的点也被relax,
虽然对逻辑没影响但会修改from和distTo的值导致test测试的结果不准确。
*/
function testHasCycleAndDeleteOne(){
var marked=[]
var from=[]
var onStack=[]
for(let i=0;i<V;i++){
testHasCycleAndDeleteOne_(i,marked,onStack,from)
if(hasCycle){
return
}
}
}
function testHasCycleAndDeleteOne_(v,marked,onStack,from){
marked[v]=true
onStack[v]=true
for(let j in G[v]){
//自己写的代码放在最上面,书上放这里,考虑到大部分时间在这个循环里,写这里更快
if(hasCycle)return true
let w=G[v][j][0]
if(!marked[w]){
from[w]=v
testHasCycleAndDeleteOne_(w,marked,onStack,from)
}else if(onStack[w]){
hasCycle=true
console.log('has cycle and delete--->',v,G[v].splice(j,1))
}
}
onStack[v]=false
}
function DepthFirstOrder(V,G){ //拓扑排序
for(let i=0;i<V;i++){
if(!marked[i]){dfs(i,G)}
}
}
function dfs(v,G){ //拓扑排序用的dfs
marked[v]=true
for(let j in G[v]){
let w=G[v][j][0]
if(!marked[w]){dfs(w,G)}
}
topoList.unshift(v)
}
//无环加权有向图的最短路径算法,属于这个算法的只有两个方法,其他都是测试用
function acyclicSP(topoList,G){
for(let i in topoList){
relax(topoList[i],G)
}
}
function relax(v,G){ //放松点v的所有边
for(let i in G[v]){
let e=G[v][i]
let w=e[0]
let d=e[1]
if(dist[v]+d<dist[w]){
dist[w]=dist[v]+d
from[w]=v
}
}
}
function dijkstra(v,G){
var pq=[]
var dist=[0]
var from=[]
let maxDist=Math.pow(2,31)-1
for(let i=1;i<V;i++){
dist.push(maxDist)
}
pq.push([0,0,0])
while(pq.length>0){
relaxDijkstra(deleteMin(pq),G,pq,dist,from)
}
return [from,dist]
}
function relaxDijkstra(e1,G,pq,dist,from){
let v=e1[1]
for(let i in G[v]){
let e=G[v][i]
let w=e[0]
let d=e[1]
if(dist[v]+d<dist[w]){
dist[w]=dist[v]+d
from[w]=v
pq.push([v,w,d])
}
}
}
function getWay(v,from_){
var ways=[]
while(v!=0){
ways.unshift(v)
v=from_[v]
}
ways.unshift(0)
return ways
}
//bellman-ford算法
function bf(start,G){
var pq=[]
var dist=[0]
let maxDist=Math.pow(2,31)-1
for(let i=1;i<V;i++){dist[i]=maxDist}
var from=[]
pq.push(start)
while(pq.length>0){
relax11(pq.pop(),G,from,dist,pq)
}
return [from,dist]
}
function relax11(v,G,from,dist,pq){
for(let i in G[v]){
let e=G[v][i]
let w=e[0],d=e[1]
if(dist[w]>dist[v]+d){
dist[w]=dist[v]+d
from[w]=v
if(pq.indexOf(w)==-1){pq.push(w)}
}
}
}
var hasCycle=false
let V=99
var pq=[]
var dist=[0]
var from=[]
var marked=[]
var topoList=[]
let maxDist=Math.pow(2,31)-1
for(let i=1;i<V;i++){
dist.push(maxDist)
}
let generateDirectedGraph=require('./wgraph').generateDirectedGraph
let generateEdges=require('./wgraph').generateEdges
let es=generateEdges(V,V*2,9,0)
var G=generateDirectedGraph(V,es,false)
DepthFirstOrder(V,G)
//检测是否有环,有删除一条边,直到无环为止
while(true){
testHasCycleAndDeleteOne()
if(!hasCycle){break}
hasCycle=false
}
if(!hasCycle){
for(let i=0;i<V;i++){console.log(i,':',G[i])}
console.log('topoList-->',topoList)
acyclicSP(topoList,G)
//console.log(from,'\n',dist)
}
let res=dijkstra(0,G)
let fromDijkstra=res[0]
//console.log('fromDijkstra->',fromDijkstra)
//可能到一个点有多条最短路径,用getWay打印路径进行人工测试
for(let i=0;i<V;i++){
if(from[i]!=fromDijkstra[i]){
//getWay可能出现死循环,dijkstra的负边导致start不经过的点也被relax,所以这些点的from最终是undefined,无法跳出v!=0的循环
console.log(getWay(i,from),getWay(i,fromDijkstra),dist[i])
}
}
console.log(JSON.stringify(from)==JSON.stringify(fromDijkstra))
console.log(JSON.stringify(dist)==JSON.stringify(res[1]))
let res1=bf(0,G)
console.log(JSON.stringify(from)==JSON.stringify(res1[0]))
console.log(JSON.stringify(dist)==JSON.stringify(res1[1]))