O(V + E)
V
: number of verticesE
: number of edgesDFS goes through the graph depth-first without regard for which edge it takes next until it cannot go any furhter. When it can't go any further, it backtracks and continues.
node 0
node 9
n = number of nodes in graph
g = adjacency list representing graph
visited = [false] * n # all false since none of the nodes is visited
function dfs(at):
if visited[at]: return # check if node is already visited
visited[at] = true # if not visited, set to true
# dfs for all neighboring nodes
neighbors = graph[at]
for next in neighbors:
dfs(next)
# Start DFS at node zero
start_node = 0
dfs(start_node)
Connected components: sometimes a graph is split into multiple copmonents
Make sure all nodes are labeled from [0, n) where n is the number of nodes
2
Start DFS at every node except if the node is visited
Mark all reachable nodes as being part of the same component (same id label)
n = number of nodes in the graph
g = adjaceny list representing graph
count = 0 # tracks number of connected components
components = empty integer array of size n # integer array that holds the integer value of which component a node belongs to
visited = [false] * n # all false since none of the nodes is visited
function findComponents():
for i in range(n):
if not visited[i]: # check if node is visited & simply skip if already visited (no backtracking)
count ++
dfs(i) # execute dfs for every unvisited node
return (count, components)
function dfs(at):
visited[at] = true
components[at] = count
for next in g[at]:
if !visited[next]:
dfs(next)
O(V + E)
V
: number of vertices in graphE
: number of edges in graphUse a queue data structure to track which node to visit next.
Upon reaching a new node the algorithm adds it to the queue to visit it later
Keep a queue of starter node and add the starter node's all neighbors to the queue
Move onto next node in queue and add the node's all neighbors to the queue
If next node is already in the queue, skip it
Repeat until we run out of nodes
n = number of nodes in the graph
g = adjacency list representing unweighted graph
# s = start node, e = end node, 0 <= e, s, < n
# returns the shortest path of nodes from s to e
function bfs(s, e):
prev = solve(s)
return reconstructPath(s, e, prev)
function solve(s):
# initialize queue data structure
q = queue data structure
q.enqueue(s)
visited = [false]*n
visited[s] = true
prev = [null]*n
while !q.isEmpty():
node = q.dequeue()
neighbors = g.get(node)
for next in neighbors:
if !visited[next]:
q.enqueue(next)
visited[next] = true
prev[next] = node
return prev
function reconstructPath(s, e, prev):
# Reconstruct path going backwards from e
path = []
for (at = e; at != null, at = prev[at]):
path.add(at)
path.reverse() # necessary because we reconstructed path backwards
# if s and e are connected, return the path
if path[0] == s:
return path
return []