-
-
Save PandaWhoCodes/8e9fc8a0ae71d717b595c1384cc72b4e to your computer and use it in GitHub Desktop.
Dijkstra's algorithm — Python
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Zaz Brown | |
# github.com/zaz/dijkstra | |
"""An efficient algorithm to find shortest paths between nodes in a graph.""" | |
from collections import defaultdict | |
class Digraph(object): | |
def __init__(self, nodes=[]): | |
self.nodes = set() | |
self.neighbours = defaultdict(set) | |
self.dist = {} | |
def addNode(self, *nodes): | |
[self.nodes.add(n) for n in nodes] | |
def addEdge(self, frm, to, d=1e309): | |
self.addNode(frm, to) | |
self.neighbours[frm].add(to) | |
self.dist[ frm, to ] = d | |
def dijkstra(self, start, maxD=1e309): | |
"""Returns a map of nodes to distance from start and a map of nodes to | |
the neighbouring node that is closest to start.""" | |
# total distance from origin | |
tdist = defaultdict(lambda: 1e309) | |
tdist[start] = 0 | |
# neighbour that is nearest to the origin | |
preceding_node = {} | |
unvisited = self.nodes | |
while unvisited: | |
current = unvisited.intersection(tdist.keys()) | |
if not current: break | |
min_node = min(current, key=tdist.get) | |
unvisited.remove(min_node) | |
for neighbour in self.neighbours[min_node]: | |
d = tdist[min_node] + self.dist[min_node, neighbour] | |
if tdist[neighbour] > d and maxD >= d: | |
tdist[neighbour] = d | |
preceding_node[neighbour] = min_node | |
return tdist, preceding_node | |
def min_path(self, start, end, maxD=1e309): | |
"""Returns the minimum distance and path from start to end.""" | |
tdist, preceding_node = self.dijkstra(start, maxD) | |
dist = tdist[end] | |
backpath = [end] | |
try: | |
while end != start: | |
end = preceding_node[end] | |
backpath.append(end) | |
path = list(reversed(backpath)) | |
except KeyError: | |
path = None | |
return dist, path | |
def dist_to(self, *args): return self.min_path(*args)[0] | |
def path_to(self, *args): return self.min_path(*args)[1] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
def main():
graph = Digraph(nodes = ['A','B','C','D','E','F','G'])
graph.addEdge("A", "B", 7)
graph.addEdge("A", "D", 5)
graph.addEdge("B", "C", 8)
graph.addEdge("B", "D", 9)
graph.addEdge("B", "E", 7)
graph.addEdge("C", "E", 5)
graph.addEdge("D", "E", 15)
graph.addEdge("D", "F", 6)
graph.addEdge("E", "F", 8)
graph.addEdge("E", "G", 9)
graph.addEdge("F", "G", 11)
print(graph.dijkstra("A"))
# print(graph.min_path("A","D"))
# print(graph.min_path("A","E"))
# print(graph.min_path("F","G"))
# print(graph.min_path("F","E"))
if name == "main":
main()