package dijkstra import ( "container/heap" "math" "reflect" "testing" ) // Edge represents a weighted directed edge to another node. type Edge struct { To int Weight int } // Dijkstra returns the shortest distances from start to every reachable node. // Unreachable nodes keep distance math.MaxInt. func Dijkstra(graph [][]Edge, start int) []int { dist := make([]int, len(graph)) for i := range dist { dist[i] = math.MaxInt } dist[start] = 0 pq := priorityQueue{{node: start, dist: 0}} heap.Init(&pq) for pq.Len() > 0 { cur := heap.Pop(&pq).(item) if cur.dist != dist[cur.node] { continue } for _, edge := range graph[cur.node] { nextDist := cur.dist + edge.Weight if nextDist < dist[edge.To] { dist[edge.To] = nextDist heap.Push(&pq, item{node: edge.To, dist: nextDist}) } } } return dist } type item struct { node int dist int } type priorityQueue []item func (pq priorityQueue) Len() int { return len(pq) } func (pq priorityQueue) Less(i, j int) bool { return pq[i].dist < pq[j].dist } func (pq priorityQueue) Swap(i, j int) { pq[i], pq[j] = pq[j], pq[i] } func (pq *priorityQueue) Push(x any) { *pq = append(*pq, x.(item)) } func (pq *priorityQueue) Pop() any { old := *pq n := len(old) x := old[n-1] *pq = old[:n-1] return x } func TestDijkstra(t *testing.T) { graph := [][]Edge{ {{To: 1, Weight: 4}, {To: 2, Weight: 1}}, {{To: 3, Weight: 1}}, {{To: 1, Weight: 2}, {To: 3, Weight: 5}}, {}, } got := Dijkstra(graph, 0) want := []int{0, 3, 1, 4} if !reflect.DeepEqual(got, want) { t.Fatalf("Dijkstra() = %v, want %v", got, want) } } func TestDijkstraUnreachable(t *testing.T) { graph := [][]Edge{ {{To: 1, Weight: 7}}, {}, {}, } got := Dijkstra(graph, 0) want := []int{0, 7, math.MaxInt} if !reflect.DeepEqual(got, want) { t.Fatalf("Dijkstra() = %v, want %v", got, want) } }