Start from the start node. Pick the node with lowest distance and update distance to its neighbors. Break out early to find min distance to end node only.
graph: s 4 e 1 1 a 1 b order of nodes: s, a, b, e path: s, e (d = 3) graph: 1 a 9 s 2 b 7 e order of nodes: s, a, b, e path: s, b, e (d = 9)
graph:
    nodes
node:
    id
    neighbors
// O(vlogv + e)
dijkstra(g, start, end):
    dist = new map()
    dist[start.id] = 0
    previous = new map()
    unvisited = new min-heap(capacity: g.nodes.count(), x => x.dist[x.n.id])
    for n in g.nodes:
        unvisited.insert({n, dist})
    while !unvisited.isempty():
        n = unvisited.delete()
        //break early to find min distance to end only
        if n == end:
            break
        for neighbor in n.neighbors:
            //no need to update dist if neighbor is visited
            if !unvisited.has(neighbor.id):
                continue
            distneighbor = n.distance-to(neighbor) + dist[n.id]
            if dist[neighbor.id] == null || distneighbor < dist[neighbor.id]:
                dist[neighbor.id] = distneighbor
                previous[neighbor.id] = n
    if previous[end.id] == null:
        return null //no path
    path = new stack()
    path.push(end.id)
    n = end
    while n.id != start.id:
        n = previous[n.id]
        path.push(n)
    return tuple(dist[end.id], path))
For A*, don't update the neighbor's distance if not within limit. If no path exists within limit then n's distance will be null (infinity).
// O(vlogv + e)
a-star(g, start, end, limit):
    dist = new map()
    dist[start.id] = 0
    previous = new map()
    unvisited = new min-heap(capacity: g.nodes.count(), x => x.dist[x.n.id])
    for n in g.nodes:
        unvisited.insert({n, dist})
    while !unvisited.isempty():
        n = unvisited.delete()
        //no path exists within limit
        if dist[n.id] == null:
            break
        //break early to find min distance to end only
        if n == end:
            break
        for neighbor in n.neighbors:
            //no need to update dist if neighbor is visited
            if !unvisited.has(neighbor.id):
                continue
            distneighbor = n.distance-to(neighbor) + dist[n.id]
            if (dist[neighbor.id] == null || distneighbor < dist[neighbor.id])
                && distneighbor <= limit:
                dist[neighbor.id] = distneighbor
                previous[neighbor.id] = n
    if previous[end.id] == null:
        return null //no path
    path = new stack()
    path.push(end.id)
    n = end
    while n.id != start.id:
        n = previous[n.id]
        path.push(n)
    return tuple(dist[end.id], path))
[Hat tip to SM]
No comments:
Post a Comment