-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathdijkstra.py
More file actions
138 lines (101 loc) · 3.8 KB
/
dijkstra.py
File metadata and controls
138 lines (101 loc) · 3.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
"""
Dijkstra's Shortest Path Algorithm
Dijkstra's algorithm finds the shortest paths from a source vertex to all other
vertices in a weighted graph with non-negative edge weights. It uses a greedy
approach, always selecting the vertex with the minimum distance.
Time Complexity: O((V + E) log V) with priority queue, O(V²) with array
Space Complexity: O(V)
Note: Does not work with negative edge weights. Use Bellman-Ford for that.
"""
import heapq
def dijkstra(graph, start):
"""
Finds shortest paths from start vertex to all other vertices.
Args:
graph: Dictionary representing weighted graph {node: [(neighbor, weight), ...]}
start: Starting vertex
Returns:
Dictionary of shortest distances {vertex: distance}
"""
# Initialize distances: all vertices start at infinity except start (0)
distances = {vertex: float('infinity') for vertex in graph}
distances[start] = 0
# Priority queue: (distance, vertex)
pq = [(0, start)]
visited = set()
while pq:
# Get vertex with minimum distance
current_dist, current_vertex = heapq.heappop(pq)
# Skip if already processed
if current_vertex in visited:
continue
visited.add(current_vertex)
# Update distances to neighbors
for neighbor, weight in graph.get(current_vertex, []):
if neighbor in visited:
continue
distance = current_dist + weight
# If found shorter path, update and add to queue
if distance < distances[neighbor]:
distances[neighbor] = distance
heapq.heappush(pq, (distance, neighbor))
return distances
def dijkstra_path(graph, start, end):
"""
Finds shortest path from start to end vertex.
Args:
graph: Dictionary representing weighted graph
start: Starting vertex
end: Target vertex
Returns:
Tuple (distance, path) where path is list of vertices
"""
distances = {vertex: float('infinity') for vertex in graph}
distances[start] = 0
previous = {vertex: None for vertex in graph}
pq = [(0, start)]
visited = set()
while pq:
current_dist, current_vertex = heapq.heappop(pq)
if current_vertex in visited:
continue
visited.add(current_vertex)
# Early termination if reached target
if current_vertex == end:
break
for neighbor, weight in graph.get(current_vertex, []):
if neighbor in visited:
continue
distance = current_dist + weight
if distance < distances[neighbor]:
distances[neighbor] = distance
previous[neighbor] = current_vertex
heapq.heappush(pq, (distance, neighbor))
# Reconstruct path
if distances[end] == float('infinity'):
return None, None
path = []
current = end
while current is not None:
path.append(current)
current = previous[current]
path.reverse()
return distances[end], path
# Example usage
if __name__ == "__main__":
# Example weighted graph: {node: [(neighbor, weight), ...]}
graph = {
'A': [('B', 4), ('C', 2)],
'B': [('C', 1), ('D', 5)],
'C': [('D', 8), ('E', 10)],
'D': [('E', 2)],
'E': []
}
print("Shortest distances from 'A':")
distances = dijkstra(graph, 'A')
for vertex, distance in distances.items():
print(f" {vertex}: {distance}")
print("\nShortest path from 'A' to 'E':")
dist, path = dijkstra_path(graph, 'A', 'E')
print(f" Distance: {dist}")
print(f" Path: {' -> '.join(path)}")