68 lines
1.5 KiB
Go
68 lines
1.5 KiB
Go
|
// Copyright (c) 2016 Bitfury Group Limited
|
||
|
// Distributed under the MIT software license, see the accompanying
|
||
|
// file LICENSE or http://www.opensource.org/licenses/mit-license.php
|
||
|
|
||
|
package graph
|
||
|
|
||
|
import "math"
|
||
|
|
||
|
func DijkstraPathWeight(g *Graph, source, target Vertex) (float64, error) {
|
||
|
dist, _, err := dijkstra(g, source, target)
|
||
|
if err != nil {
|
||
|
return 0, err
|
||
|
}
|
||
|
if _, ok := dist[target]; !ok {
|
||
|
return 0, PathNotFoundError
|
||
|
}
|
||
|
return dist[target], nil
|
||
|
}
|
||
|
|
||
|
func DijkstraPath(g *Graph, source, target Vertex) ([]Vertex, error) {
|
||
|
_, parent, err := dijkstra(g, source, target)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
if _, ok := parent[target]; !ok {
|
||
|
return nil, PathNotFoundError
|
||
|
}
|
||
|
path, err := Path(source, target, parent)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return path, nil
|
||
|
}
|
||
|
|
||
|
func dijkstra(g *Graph, source, target Vertex) (map[Vertex]float64, map[Vertex]Vertex, error) {
|
||
|
dist := make(map[Vertex]float64)
|
||
|
colored := make(map[Vertex]bool)
|
||
|
parent := make(map[Vertex]Vertex)
|
||
|
dist[source] = 0
|
||
|
for {
|
||
|
bestDist := math.MaxFloat64
|
||
|
var bestID Vertex
|
||
|
for id, val := range dist {
|
||
|
if val < bestDist && !colored[id] {
|
||
|
bestDist = val
|
||
|
bestID = id
|
||
|
}
|
||
|
}
|
||
|
if bestID == target {
|
||
|
break
|
||
|
}
|
||
|
colored[bestID] = true
|
||
|
targets, err := g.GetNeighbors(bestID)
|
||
|
if err != nil {
|
||
|
return nil, nil, err
|
||
|
}
|
||
|
for id, multiedges := range targets {
|
||
|
for _, edge := range multiedges {
|
||
|
if have, ok := dist[id]; !ok || have > dist[bestID]+edge.Wgt {
|
||
|
dist[id] = dist[bestID] + edge.Wgt
|
||
|
parent[id] = bestID
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return dist, parent, nil
|
||
|
}
|