DSA Tutorial menu

DSA Graphs, BFS and DFS

A graph is a set of points connected by lines. It can model roads, friendships, flights and networks.

What is a Graph?

Think of a map of areas in Karachi. Each area is a point and each road between two areas is a line.

WordMeaningExample
Vertex (node)A pointAn area such as Saddar
EdgeA connection between two verticesA road
NeighbourA vertex directly connected to anotherAreas one road apart
PathA route along edgesOrangi to Saddar via Nazimabad
Weighted graphEdges have a value, such as distanceA road of 12 km
Directed graphEdges go one way onlyA one-way street, or "follows" on social media

A tree is a special graph with no cycles (no way to go round in a loop).

Storing a Graph: Adjacency List

The most common way is an adjacency list: a dictionary where each vertex maps to a list of its neighbours.

Example

python
graph = {
    "Orangi": ["Nazimabad", "Baldia"],
    "Nazimabad": ["Orangi", "Saddar", "Gulshan"],
    "Baldia": ["Orangi"],
    "Saddar": ["Nazimabad", "Clifton"],
    "Gulshan": ["Nazimabad"],
    "Clifton": ["Saddar"],
}

print(graph["Nazimabad"])
print(len(graph), "areas")
edges = sum(len(n) for n in graph.values()) // 2
print(edges, "roads")
Output
['Orangi', 'Saddar', 'Gulshan']
6 areas
5 roads

Each road appears twice (once from each end), which is why we divide by 2. Another option is an adjacency matrix, a table of 0s and 1s, which is simple but uses O(V^2) memory.

Breadth-First Search (BFS)

BFS explores the graph level by level: first all neighbours of the start, then their neighbours, and so on. It uses a queue.

Example

python
from collections import deque

graph = {
    "Orangi": ["Nazimabad", "Baldia"],
    "Nazimabad": ["Orangi", "Saddar", "Gulshan"],
    "Baldia": ["Orangi"],
    "Saddar": ["Nazimabad", "Clifton"],
    "Gulshan": ["Nazimabad"],
    "Clifton": ["Saddar"],
}

def bfs(start):
    visited = [start]
    queue = deque([start])
    while queue:
        place = queue.popleft()
        for nxt in graph[place]:
            if nxt not in visited:
                visited.append(nxt)
                queue.append(nxt)
    return visited

print(bfs("Orangi"))
Output
['Orangi', 'Nazimabad', 'Baldia', 'Saddar', 'Gulshan', 'Clifton']

In a graph where every edge counts the same, BFS finds the path with the fewest edges. Apps use this idea to find routes with the fewest stops.

Shortest Path with BFS

By remembering where we came from, BFS can rebuild the route:

Example

python
from collections import deque

graph = {
    "Orangi": ["Nazimabad", "Baldia"],
    "Nazimabad": ["Orangi", "Saddar", "Gulshan"],
    "Baldia": ["Orangi"],
    "Saddar": ["Nazimabad", "Clifton"],
    "Gulshan": ["Nazimabad"],
    "Clifton": ["Saddar"],
}

def shortest_path(start, goal):
    came_from = {start: None}
    queue = deque([start])
    while queue:
        place = queue.popleft()
        if place == goal:
            break
        for nxt in graph[place]:
            if nxt not in came_from:
                came_from[nxt] = place
                queue.append(nxt)
    path = []
    while goal is not None:
        path.append(goal)
        goal = came_from[goal]
    return path[::-1]

print(" -> ".join(shortest_path("Baldia", "Clifton")))
Output
Baldia -> Orangi -> Nazimabad -> Saddar -> Clifton

Depth-First Search (DFS)

DFS goes as deep as possible along one path before coming back to try another. It uses recursion (or a stack).

Example

python
graph = {
    "A": ["B", "C"],
    "B": ["D", "E"],
    "C": ["F"],
    "D": [],
    "E": ["F"],
    "F": [],
}

def dfs(node, visited=None):
    if visited is None:
        visited = []
    visited.append(node)
    for nxt in graph[node]:
        if nxt not in visited:
            dfs(nxt, visited)
    return visited

print(dfs("A"))
Output
['A', 'B', 'D', 'E', 'F', 'C']

BFS vs DFS

BFSDFS
UsesA queueA stack or recursion
ExploresLevel by levelOne branch fully, then the next
Good forFewest-edge paths, nearby friendsFinding any path, detecting cycles, puzzles and mazes
TimeO(V + E)O(V + E)

V is the number of vertices and E the number of edges. For roads with distances (weighted graphs), Dijkstra's algorithm finds the shortest total distance.

Exercise

Exercise

Which data structure does breadth-first search (BFS) use to decide which vertex to visit next?

Learn DSA with a teacher

Join the Python Programming course at Workownix, online or in Orangi Town, Karachi, and get a certificate.

See the course Ask on WhatsApp