Welcome to Day 67 of the #80DaysOfChallenges journey! This intermediate challenge implements Breadth-First Search (BFS) to find the shortest path in an unweighted graph, using a queue for level-order traversal and a parent dict for path reconstruction, achieving optimal O(V+E) time where V is vertices and E edges. It handles dict adjacency for graphs, deque for efficient FIFO, and reconstructs the actual path list, making it essential for routing, networking, or game AI like maze solving. If you're advancing from basic queues to graph algorithms or prepping for interviews with shortest path questions (LeetCode #1129 style), this "Python BFS shortest path" script demonstrates a function that's robust, reconstructs paths, and easy to adapt for weighted graphs or distances.
💡 Key Takeaways from Day 67: BFS Shortest Path Function
This task features a function that uses BFS to explore levels, track parents for backtracking, and return the path list or None. It's a standard BFS pattern: enqueue start, dequeue/visit/enqueue neighbors, use parent for path. We'll detail: function with queue and parent dict, loop for traversal and enqueue, and path reconstruction with main demo.
1. Function Design: Queue, Visited, Parent Setup
The shortest_path_bfs function takes graph dict, start, target, returns path list:
def shortest_path_bfs(graph: dict, start, target):
"""Return the shortest path from start to target using BFS."""
queue = deque([start]) # queue for BFS traversal
visited = {start} # track visited nodes
parent = {start: None} # store parent to reconstruct path
Deque for O(1) popleft/append. Visited set prevents revisits. Parent dict tracks came-from for path build.
2. Loop Processing: Dequeue, Check Target, Enqueue Neighbors
Core while explores:
while queue:
node = queue.popleft() # process next node in BFS order
if node == target:
break # shortest path found
for neighbor in graph.get(node, []):
if neighbor not in visited:
visited.add(neighbor) # mark as visited
parent[neighbor] = node # record where we came from
queue.append(neighbor) # add to BFS queue
Popleft dequeues, breaks on target (BFS guarantees shortest). Enqueues unvisited neighbors, sets parent. graph.get(node, []) handles isolates.
3. Path Reconstruction: Backtrack from Target
After loop, build path:
# reconstruct path if target was reached
if target not in parent:
return None
path = []
curr = target
while curr is not None:
path.append(curr)
curr = parent[curr]
return path[::-1] # reverse path (start -> target)
If target not reached, None. Else backtrack append, reverse for start-to-target.
4. Main Demo: Defined Graph and Print
Demo with dict graph:
graph = {
"A": ["B", "C"],
"B": ["D", "E"],
"C": ["F"],
"D": [],
"E": ["F"],
"F": []
}
start_node = "A"
target_node = "F"
print("Graph:", graph)
print(f"Finding shortest path from {start_node} to {target_node}")
path = shortest_path_bfs(graph, start_node, target_node)
if path is None:
print("No path found.")
else:
print(f"Shortest path: {path}")
print(f"Path length: {len(path) - 1}")
Prints graph, runs BFS from A to F, shows path like ['A', 'C', 'F'], length 2.
🎯 Summary and Reflections
This BFS shortest path uses queue for levels, parent for reconstruction. It reinforced:
- BFS for unweighted shortest: Levels guarantee minimal steps.
- Parent tracking: Essential for path, not just distance.
- Get for neighbors: Handles missing keys gracefully.
Reflections: Add distance with level counter. For graphs, visited prevents cycles.
Advanced Alternatives: Dijkstra for weights. A* with heuristics. Multi-source BFS. Your path find? Share!
🚀 Next Steps and Resources
Day 67 routed graphs efficiently. In #80DaysOfChallenges? Weighted? Post!
- Source Code for Challenge #67: scripts/shortest_path_bfs.py
- Main Repository: 80-days-of-challenges
- Daily Updates: Twitter/X (@Shahrouzlogs)
Top comments (0)