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 "container/list"
|
||
|
|
||
|
func ShortestPathLen(g *Graph, v1, v2 Vertex) (int, error) {
|
||
|
dist, _, err := bfs(g, v1, v2)
|
||
|
if err != nil {
|
||
|
return 0, err
|
||
|
}
|
||
|
if _, ok := dist[v2]; !ok {
|
||
|
return 0, PathNotFoundError
|
||
|
}
|
||
|
return dist[v2], nil
|
||
|
}
|
||
|
|
||
|
func ShortestPath(g *Graph, v1, v2 Vertex) ([]Vertex, error) {
|
||
|
_, parent, err := bfs(g, v1, v2)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
if _, ok := parent[v2]; !ok {
|
||
|
return nil, PathNotFoundError
|
||
|
}
|
||
|
path, err := Path(v1, v2, parent)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return path, nil
|
||
|
}
|
||
|
|
||
|
func bfs(g *Graph, v1, v2 Vertex) (map[Vertex]int, map[Vertex]Vertex, error) {
|
||
|
var queue list.List
|
||
|
queue.PushBack(v1)
|
||
|
dist := make(map[Vertex]int)
|
||
|
parent := make(map[Vertex]Vertex)
|
||
|
dist[v1] = 0
|
||
|
for queue.Len() != 0 {
|
||
|
err := ibfs(g, queue.Front().Value.(Vertex), &queue, dist, parent)
|
||
|
if err != nil {
|
||
|
return nil, nil, err
|
||
|
}
|
||
|
if _, ok := dist[v2]; ok {
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
return dist, parent, nil
|
||
|
}
|
||
|
|
||
|
func ibfs(g *Graph, v Vertex, queue *list.List, dist map[Vertex]int, parent map[Vertex]Vertex) error {
|
||
|
queue.Remove(queue.Front())
|
||
|
targets, err := g.GetNeighbors(v)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
for to := range targets {
|
||
|
if _, ok := dist[to]; !ok {
|
||
|
dist[to] = dist[v] + 1
|
||
|
parent[to] = v
|
||
|
queue.PushBack(to)
|
||
|
}
|
||
|
}
|
||
|
return nil
|
||
|
}
|