134 строки
2.7 KiB
Go
134 строки
2.7 KiB
Go
// Copyright 2011 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// Simple demonstration of a graph interface and
|
|
// Dijkstra's algorithm built on top of that interface,
|
|
// without using inheritance.
|
|
|
|
package graph
|
|
|
|
import "container/heap"
|
|
|
|
// A Graph is the interface implemented by graphs that
|
|
// this package can run algorithms on.
|
|
type Graph interface {
|
|
// NumVertex returns the number of vertices in the graph.
|
|
NumVertex() int
|
|
|
|
// VertexID returns a vertex ID, 0 <= ID < NumVertex(), for v.
|
|
VertexID(v Vertex) int
|
|
|
|
// Neighbors returns a slice of vertices that are adjacent
|
|
// to v in the graph.
|
|
Neighbors(v Vertex) []Vertex
|
|
}
|
|
|
|
type Vertex interface {
|
|
String() string
|
|
}
|
|
|
|
// ShortestPath uses Dijkstra's algorithm to find the shortest
|
|
// path from start to end in g. It returns the path as a slice of
|
|
// vertices, with start first and end last. If there is no path,
|
|
// ShortestPath returns nil.
|
|
func ShortestPath(g Graph, start, end Vertex) []Vertex {
|
|
d := newDijkstra(g)
|
|
|
|
d.visit(start, 1, nil)
|
|
for !d.empty() {
|
|
p := d.next()
|
|
if g.VertexID(p.v) == g.VertexID(end) {
|
|
break
|
|
}
|
|
for _, v := range g.Neighbors(p.v) {
|
|
d.visit(v, p.depth+1, p)
|
|
}
|
|
}
|
|
|
|
p := d.pos(end)
|
|
if p.depth == 0 {
|
|
// unvisited - no path
|
|
return nil
|
|
}
|
|
path := make([]Vertex, p.depth)
|
|
for ; p != nil; p = p.parent {
|
|
path[p.depth-1] = p.v
|
|
}
|
|
return path
|
|
}
|
|
|
|
// A dpos is a position in the Dijkstra traversal.
|
|
type dpos struct {
|
|
depth int
|
|
heapIndex int
|
|
v Vertex
|
|
parent *dpos
|
|
}
|
|
|
|
// A dijkstra is the Dijkstra traversal's work state.
|
|
// It contains the heap queue and per-vertex information.
|
|
type dijkstra struct {
|
|
g Graph
|
|
q []*dpos
|
|
byID []dpos
|
|
}
|
|
|
|
func newDijkstra(g Graph) *dijkstra {
|
|
d := &dijkstra{g: g}
|
|
d.byID = make([]dpos, g.NumVertex())
|
|
return d
|
|
}
|
|
|
|
func (d *dijkstra) pos(v Vertex) *dpos {
|
|
p := &d.byID[d.g.VertexID(v)]
|
|
p.v = v // in case this is the first time we've seen it
|
|
return p
|
|
}
|
|
|
|
func (d *dijkstra) visit(v Vertex, depth int, parent *dpos) {
|
|
p := d.pos(v)
|
|
if p.depth == 0 {
|
|
p.parent = parent
|
|
p.depth = depth
|
|
heap.Push(d, p)
|
|
}
|
|
}
|
|
|
|
func (d *dijkstra) empty() bool {
|
|
return len(d.q) == 0
|
|
}
|
|
|
|
func (d *dijkstra) next() *dpos {
|
|
return heap.Pop(d).(*dpos)
|
|
}
|
|
|
|
// Implementation of heap.Interface
|
|
func (d *dijkstra) Len() int {
|
|
return len(d.q)
|
|
}
|
|
|
|
func (d *dijkstra) Less(i, j int) bool {
|
|
return d.q[i].depth < d.q[j].depth
|
|
}
|
|
|
|
func (d *dijkstra) Swap(i, j int) {
|
|
d.q[i], d.q[j] = d.q[j], d.q[i]
|
|
d.q[i].heapIndex = i
|
|
d.q[j].heapIndex = j
|
|
}
|
|
|
|
func (d *dijkstra) Push(x interface{}) {
|
|
p := x.(*dpos)
|
|
p.heapIndex = len(d.q)
|
|
d.q = append(d.q, p)
|
|
}
|
|
|
|
func (d *dijkstra) Pop() interface{} {
|
|
n := len(d.q)
|
|
x := d.q[n-1]
|
|
d.q = d.q[:n-1]
|
|
x.heapIndex = -1
|
|
return x
|
|
}
|