Algorithms: BFS, DFS, A*, Uniform Cost
Description
Search algorithms help AI systems explore a problem space to find solutions. Four essential ones are:
- Breadth-First Search (BFS): Explores nodes level by level. Guarantees the shortest path in unweighted graphs.
- Depth-First Search (DFS): Explores deep into one branch before backtracking. Memory-efficient but may get stuck.
- Uniform Cost Search (UCS): Expands the least-cost node first. Best for weighted graphs with no heuristic.
- A*: Combines actual cost from the start (g) and estimated cost to the goal (h) using f(n) = g(n) + h(n).
Examples (Code)
Below is a simple example
#BFS Example in Python
from collections import deque
def bfs(graph, start, goal):
queue = deque([[start]])
visited = set()
while queue:
path = queue.popleft()
node = path[-1]
if node == goal:
return path
if node not in visited:
visited.add(node)
for neighbor in graph.get(node, []):
new_path = list(path)
new_path.append(neighbor)
queue.append(new_path)
return None
#DFS Example in Python
def dfs(graph, start, goal, path=None, visited=None):
if path is None:
path = [start]
if visited is None:
visited = set()
visited.add(start)
if start == goal:
return path
for neighbor in graph.get(start, []):
if neighbor not in visited:
new_path = dfs(graph, neighbor, goal, path + [neighbor], visited)
if new_path:
return new_path
return None
#Uniform Cost Search (UCS) Example
import heapq
def ucs(graph, start, goal):
queue = [(0, [start])]
visited = set()
while queue:
cost, path = heapq.heappop(queue)
node = path[-1]
if node == goal:
return path, cost
if node not in visited:
visited.add(node)
for neighbor, weight in graph.get(node, []):
heapq.heappush(queue, (cost + weight, path + [neighbor]))
return None, float('inf')
#A* Search Example
import heapq
def a_star(graph, start, goal, heuristic):
queue = [(0 + heuristic[start], 0, [start])]
visited = set()
while queue:
est_total, cost, path = heapq.heappop(queue)
node = path[-1]
if node == goal:
return path, cost
if node not in visited:
visited.add(node)
for neighbor, weight in graph.get(node, []):
new_cost = cost + weight
est = new_cost + heuristic.get(neighbor, 0)
heapq.heappush(queue, (est, new_cost, path + [neighbor]))
return None, float('inf')
Real-World Applications
Google Maps
Uses A* and UCS to find shortest and fastest routes based on traffic and distance.
Game AI
NPCs use A* and DFS for pathfinding in open-world environments.
Web Crawlers
Use BFS to traverse web pages efficiently across levels.
Autonomous Robots
Use A* or UCS for obstacle-free navigation and energy-efficient motion planning.
Where AI Is Applied
Field | Application |
---|---|
Navigation | GPS route planning using A* and UCS |
Game Development | Enemy pathfinding using A* or DFS |
Web Search | Web crawlers using BFS to explore content |
Network Routing | Data packet routing using UCS |
AI Planning | Goal-oriented problem solving using informed search |
Resources
Additional resources
Interview Questions with Answers
What is the difference between BFS and DFS?
BFS explores level-by-level using a queue and guarantees shortest path in unweighted graphs. DFS explores deeply using a stack or recursion but may not find the shortest path.
When should you use Uniform Cost Search?
Use UCS when path costs vary and there’s no heuristic information available.
What does A* search optimize?
A* balances path cost and goal estimation, making it both complete and optimal when the heuristic is admissible.
What is the main drawback of DFS?
DFS can get stuck in infinite or long paths and doesn't always find the optimal solution.
What makes A* optimal?
If the heuristic used is admissible (never overestimates the cost), A* guarantees the optimal path.