Understanding Stack Operations & Implementation
From Riyadh to Makkah: Programming Depth-First Searchstack = [start] - Initialize stackstack.pop() - Pop (LIFO)stack.append() - Push (add to top)len(stack) - Check if emptylist - Simple stack implementationset - Fast lookup for visited citiesdict - Parent mapping for path reconstructiondef dfs_search(graph, start, goal):
"""
Find a path using DFS (Depth-First Search)
Args:
graph: dict of city connections {city: [neighbors]}
start: starting city name (string)
goal: destination city name (string)
Returns:
list: path from start to goal (may not be shortest)
None: if no path exists
Time Complexity: O(V + E) where V=vertices, E=edges
Space Complexity: O(V) for stack and visited set
"""
# Step 1: Initialize data structures
stack = [start] # LIFO stack for DFS
visited = set([start]) # Track visited cities
parent = {start: None} # Track parent for path reconstruction
print(f"π Starting DFS from {start} to {goal}")
print(f"π Initial stack: {stack}")
# Step 2: DFS main loop
while stack:
# Pop: Remove last city from stack (LIFO)
current = stack.pop()
print(f"\nπ Processing: {current}")
print(f"π Stack after pop: {stack}")
# Step 3: Check if goal reached
if current == goal:
print(f"π― Goal {goal} found!")
# Reconstruct path by following parent pointers
path = []
temp = current
while temp is not None:
path.append(temp)
temp = parent[temp]
return path[::-1] # Reverse to get startβgoal order
# Step 4: Explore all neighbors of current city
neighbors = graph.get(current, [])
print(f"π Exploring neighbors of {current}: {neighbors}")
# Add neighbors to stack (in reverse order for consistent exploration)
for neighbor in reversed(neighbors):
if neighbor not in visited:
# Mark as visited to avoid cycles
visited.add(neighbor)
# Set parent for path reconstruction
parent[neighbor] = current
# Push: Add to top of stack
stack.append(neighbor)
print(f" β Pushed {neighbor} to stack (via {current})")
print(f"π Stack after exploring {current}: {stack}")
print(f"β
Visited cities: {visited}")
print(f"β No path found from {start} to {goal}")
return None # No path exists
def dfs_recursive(graph, current, goal, visited=None, parent=None, path=None):
"""
Recursive DFS implementation (alternative approach)
Args:
graph: dict of city connections
current: current city being processed
goal: destination city
visited: set of visited cities (for recursion)
parent: parent mapping (for recursion)
path: current path being built (for recursion)
Returns:
list: path from start to goal, or None if no path
"""
if visited is None:
visited = set()
if parent is None:
parent = {}
if path is None:
path = []
# Mark current as visited
visited.add(current)
path.append(current)
print(f"π Visiting {current}, Path so far: {path}")
# Check if goal reached
if current == goal:
print(f"π― Goal {goal} found via recursion!")
return path.copy()
# Recursively explore neighbors
neighbors = graph.get(current, [])
for neighbor in neighbors:
if neighbor not in visited:
parent[neighbor] = current
result = dfs_recursive(graph, neighbor, goal, visited, parent, path)
if result: # Path found
return result
# Backtrack: remove current from path
path.pop()
print(f"π Backtracking from {current}")
return None # No path found in this branch
def print_dfs_analysis(graph, start, goal):
"""Run DFS with detailed analysis"""
print("="*60)
print("π§ DFS ALGORITHM ANALYSIS")
print("="*60)
print("\n--- ITERATIVE DFS ---")
path_iterative = dfs_search(graph, start, goal)
print("\n--- RECURSIVE DFS ---")
path_recursive = dfs_recursive(graph, start, goal)
print("\n--- COMPARISON ---")
if path_iterative:
print(f"π Iterative DFS Path: {' β '.join(path_iterative)}")
print(f"π Path length: {len(path_iterative) - 1} hops")
else:
print("π Iterative DFS: No path found")
if path_recursive:
print(f"π Recursive DFS Path: {' β '.join(path_recursive)}")
print(f"π Path length: {len(path_recursive) - 1} hops")
else:
print("π Recursive DFS: No path found")
# Our Saudi cities network (same as BFS demo)
cities_graph = {
'Riyadh': ['Qassim', 'Jeddah'], # Capital city: 2 connections
'Qassim': ['Riyadh', 'Medina'], # Central region: 2 connections
'Medina': ['Qassim', 'Jeddah'], # Holy city: 2 connections
'Jeddah': ['Riyadh', 'Medina', 'Makkah'], # Port city: 3 connections
'Makkah': ['Jeddah'] # Holy city: 1 connection
}
# Example usage
if __name__ == "__main__":
print_dfs_analysis(cities_graph, 'Riyadh', 'Makkah')
# Try different start/goal combinations
print("\n" + "="*40)
print("π TESTING OTHER ROUTES")
print("="*40)
test_cases = [
('Riyadh', 'Medina'),
('Qassim', 'Makkah'),
('Medina', 'Riyadh')
]
for start, goal in test_cases:
path = dfs_search(cities_graph, start, goal)
result = f"{' β '.join(path)}" if path else "No path"
print(f"π {start} to {goal}: {result}")
This shows exactly what you'll see when running the Python code:
$ python dfs_search.py
============================================================
π§ DFS ALGORITHM ANALYSIS
============================================================
π Starting DFS from Riyadh to Makkah
π Initial stack: ['Riyadh']
π Processing: Riyadh
π Stack after pop: []
π Exploring neighbors of Riyadh: ['Qassim', 'Jeddah']
β Pushed Jeddah to stack (via Riyadh)
β Pushed Qassim to stack (via Riyadh)
π Stack after exploring Riyadh: ['Jeddah', 'Qassim']
β
Visited cities: {'Riyadh', 'Qassim', 'Jeddah'}
π Processing: Qassim
π Stack after pop: ['Jeddah']
π Exploring neighbors of Qassim: ['Riyadh', 'Medina']
β Pushed Medina to stack (via Qassim)
π Stack after exploring Qassim: ['Jeddah', 'Medina']
β
Visited cities: {'Riyadh', 'Qassim', 'Jeddah', 'Medina'}
π Processing: Medina
π Stack after pop: ['Jeddah']
π Exploring neighbors of Medina: ['Qassim', 'Jeddah']
π Stack after exploring Medina: ['Jeddah']
β
Visited cities: {'Riyadh', 'Qassim', 'Jeddah', 'Medina'}
π Processing: Jeddah
π Stack after pop: []
π Exploring neighbors of Jeddah: ['Riyadh', 'Medina', 'Makkah']
β Pushed Makkah to stack (via Jeddah)
π Stack after exploring Jeddah: ['Makkah']
β
Visited cities: {'Riyadh', 'Qassim', 'Jeddah', 'Medina', 'Makkah'}
π Processing: Makkah
π Stack after pop: []
π― Goal Makkah found!
π SUCCESS! Path found: Riyadh β Qassim β Medina β Jeddah β Makkah
π Path length: 4 hops
ποΈ Cities in path: 5
Try these modifications to deepen your understanding: