Lecture 14: Graph Traversals
CSE 373: Data Structures and Algorithms
CSE 373 22 SP – CHAMPION
1
Administrivia
P3 due August 3rd 11:59PM
EC 2 Survey due Tomorrow at 11:59P
Final Exam Date
Warm Up
Profiles
Follows and friendships
Directed
Unweighted
https://tinyurl.com/Summer373L14
Introduction to Graphs
CSE 373 SP 18 - KASEY CHAMPION
4
Graph: Formal Definition
CSE 373 SP 18 - KASEY CHAMPION
5
A
B
C
D
E
F
G
H
V = { A, B, C, D, E, F, G, H }
E = { (A, B), (A, C), (A, D), (A, H),
(C, B), (B, D), (D, E), (D, F),
(F, G), (G, H)}
Graph Glossary
( , )
a
b
c
V: Set of vertices
E: Set of edges
a
b
( , )
a
c
( , )
c
d
…
…
a
b
c
e
d
Adjacency Matrix - Runtime
CSE 373 SU 19 – ROBBIE WEBBER
| 0 | 1 | 2 | 3 | 4 | 5 | 6 |
0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 |
1 | 1 | 0 | 0 | 1 | 0 | 0 | 0 |
2 | 1 | 0 | 0 | 1 | 0 | 0 | 0 |
3 | 0 | 1 | 1 | 0 | 0 | 1 | 0 |
4 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
5 | 0 | 0 | 0 | 1 | 1 | 0 | 0 |
6 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
6
2
3
4
5
0
1
In an adjacency matrix a[u][v] is 1 if there is an edge (u,v), and 0 otherwise.
Worst-case Time Complexity �(|V| = n, |E| = m):
Add Edge:
Remove Edge:
Check edge exists from (u,v):
Get outneighbors of u:
Get inneighbors of u:
Space Complexity:
𝚯(1)
𝚯(1)
𝚯(1)
𝚯(n)
𝚯(n)
𝚯(n * n)
Adjacency List
CSE 373 SP 20 - KASEY CHAMPION
8
A
B
C
D
Linked Lists
0 | | |
1 | | |
2 | | |
3 | | |
A
B
C
D
A
B
C
B
D
In an adjacency matrix a[u][v] is 1 if there is an edge (u,v), and 0 otherwise.
Worst-case Time Complexity �(|V| = n, |E| = m):
Add Edge:
Remove Edge:
Check edge exists from (u,v):
Get outneighbors of u:
Get inneighbors of u:
Space Complexity:
𝚯(1)
𝚯(deg(u) )
𝚯(deg (u) )
𝚯(deg(u) )
𝚯(n + m)
𝚯(n + m)
Adjacency List
CSE 373 SP 20 - KASEY CHAMPION
9
0 | 1 | 2 | 3 | 4 |
| | | | |
0 | 1 | 2 | 3 | 4 |
| | | | |
0 | 1 | 2 | 3 | 4 |
| | | | |
A
B
C
D
Hash Tables
0 | | |
1 | | |
2 | | |
3 | | |
A
B
C
D
C
D
A
B
B
In an adjacency matrix a[u][v] is 1 if there is an edge (u,v), and 0 otherwise.
Worst-case Time Complexity �(|V| = n, |E| = m):
Add Edge:
Remove Edge:
Check edge exists from (u,v):
Get outneighbors of u:
Get inneighbors of u:
Space Complexity:
𝚯(1)
𝚯(1)
𝚯(1)
𝚯(deg(u) )
𝚯(n)
𝚯(n + m)
Adapting for Undirected Graphs
| A | B | C | D | E |
A | 0 | 1 | 1 | 0 | 0 |
B | 1 | 0 | 1 | 1 | 0 |
C | 1 | 1 | 0 | 1 | 0 |
D | 0 | 1 | 1 | 0 | 0 |
E | 0 | 0 | 0 | 0 | 0 |
destination
origin
Abstraction of the Hash Map! Buckets not shown.
A
C
B
Keys (origins)
Values (hashmaps w/ destinations as keys)
B
C
1
1
B
D
1
1
B
1
A
B
C
E
D
Adjacency Matrix
Store each edge as both directions
(makes the matrix symmetrical)
Adjacency List
Store each edge as both directions
(doubles the number of entries)
A
1
C
1
A
C
1
1
D
1
D
Tradeoffs
373: Assumed Graph Implementations
Add Edge | |
Remove Edge | |
Check if edge (u, v) exists | |
Get out-neighbors of u | |
Get in-neighbors of v | |
(Space Complexity) | |
(|V| = n, |E| = m)
Graph Traversals
CSE 373 SP 18 - KASEY CHAMPION
13
s-t Connectivity Problem
s-t Connectivity Problem
Given source vertex s and a target vertex t, does there exist a path between s and t?
1
2
3
4
5
6
7
8
0
s
t
s-t Connectivity Problem: Proposed Solution
connected(Vertex s, Vertex t) {
if (s == t) {
return true;
} else {
for (Vertex n : s.neighbors) {
if (connected(n, t)) {
return true;
}
}
return false;
}
}
1
2
3
4
5
6
7
8
0
s
t
What’s wrong with this proposal?
Does 0 == 7? No; if(connected(1, 7) return true;
Does 1 == 7? No; if(connected(0, 7) return true;
Does 0 == 7?
connected(Vertex s, Vertex t) {
if (s == t) {
return true;
} else {
for (Vertex n : s.neighbors) {
if (connected(n, t)) {
return true;
}
}
return false;
}
}
1
2
3
4
5
6
7
8
0
s
t
s-t Connectivity Problem: Better Solution
Set<Vertex> visited; // assume global
connected(Vertex s, Vertex t) {
if (s == t) {
return true;
} else {
visited.add(s);
for (Vertex n : s.neighbors) {
if (!visited.contains(n)) {
if (connected(n, t)) {
return true;
}
}
}
return false;
}
}
1
2
3
4
5
6
7
8
0
s
t
This general approach for crawling through a graph is going to be the basis for a LOT of algorithms!
Set<Vertex> visited; // assume global
connected(Vertex s, Vertex t) {
if (s == t) {
return true;
} else {
visited.add(s);
for (Vertex n : s.neighbors) {
if (!visited.contains(n)) {
if (connected(n, t)) {
return true;
}
}
}
return false;
}
}
Recursive Depth-First Search (DFS)
1
2
3
4
5
6
7
8
s
VISITED
9
Set<Vertex> visited; // assume global
connected(Vertex s, Vertex t) {
if (s == t) {
return true;
} else {
visited.add(s);
for (Vertex n : s.neighbors) {
if (!visited.contains(n)) {
if (connected(n, t)) {
return true;
}
}
}
return false;
}
}
1
2
3
4
5
8
0
s
VISITED
Aside Tree Traversals
The difference between these orderings is when we “process” the root – all are DFS!
Breadth-First Search (BFS)
1
2
3
4
5
6
7
8
s
VISITED
9
We call this approach a breadth-first search (BFS)
for (Vertex n : s.neighbors) {
0
1
2
3
4
This is our goal, but how do we translate into code?
BFS Implementation
bfs(Graph graph, Vertex start) {
Our extra data structure! Will keep track of “outer edge” of nodes still to explore
Let’s make this a bit more realistic and add a Graph
Kick off the algorithm by adding start to perimeter
1
2
3
4
5
6
7
8
9
start
Grab one element at a time from the perimeter
Look at all that element’s children
Add new ones to perimeter!
Queue<Vertex> perimeter = new Queue<>();
Set<Vertex> visited = new Set<>();
perimeter.add(start);
visited.add(start);
while (!perimeter.isEmpty()) {
Vertex from = perimeter.remove();
for (Edge edge : graph.edgesFrom(from)) {
Vertex to = edge.to();
if (!visited.contains(to)) {
perimeter.add(to);
visited.add(to);
}
}
}
}
BFS Implementation: In Action
PERIMETER
bfs(Graph graph, Vertex start) {
Queue<Vertex> perimeter = new Queue<>();
Set<Vertex> visited = new Set<>();
perimeter.add(start);
visited.add(start);
while (!perimeter.isEmpty()) {
Vertex from = perimeter.remove();
for (Edge edge : graph.edgesFrom(from)) {
Vertex to = edge.to();
if (!visited.contains(to)) {
perimeter.add(to);
visited.add(to);
}
}
}
}
1
2
3
4
5
6
7
8
start
VISITED
9
|
1
2
4
5
3
6
8
9
7
BFS Intuition: Why Does it Work?
0
1
2
3
4
PERIMETER
bfs(Graph graph, Vertex start) {
Queue<Vertex> perimeter = new Queue<>();
Set<Vertex> visited = new Set<>();
perimeter.add(start);
visited.add(start);
while (!perimeter.isEmpty()) {
Vertex from = perimeter.remove();
for (Edge edge : graph.edgesFrom(from)) {
Vertex to = edge.to();
if (!visited.contains(to)) {
perimeter.add(to);
visited.add(to);
}
}
}
}
1
2
3
4
5
6
7
8
start
VISITED
9
|
1
2
4
5
3
6
8
9
7
BFS’s Evil Twin: DFS!
bfs(Graph graph, Vertex start) {
Queue<Vertex> perimeter = new Queue<>();
Set<Vertex> visited = new Set<>();
perimeter.add(start);
visited.add(start);
while (!perimeter.isEmpty()) {
Vertex from = perimeter.remove();
for (Edge edge : graph.edgesFrom(from)) {
Vertex to = edge.to();
if (!visited.contains(to)) {
perimeter.add(to);
visited.add(to);
}
}
}
}
dfs(Graph graph, Vertex start) {
Stack<Vertex> perimeter = new Stack<>();
Set<Vertex> visited = new Set<>();
perimeter.add(start);
while (!perimeter.isEmpty()) {
Vertex from = perimeter.remove();
if (!visted.contains(from)) {
for (Edge edge:graph.edgesFrom(from)) {
Vertex to = edge.to();
perimeter.add(to)
}
visited.add(from);
}
}
}
In DFS we can’t immediately add a node as “visited”. We need to make sure we are only marking the node when it is popped.
Change Queue for order to process neighbors to a Stack
Recap: Graph Traversals
BFS
(Iterative)
DFS
(Iterative)
DFS
(Recursive)
Be careful using this – on huge graphs, might overflow the call stack
Let’s Practice Now!
Using BFS for the s-t Connectivity Problem
s-t Connectivity Problem
Given source vertex s and a target vertex t, does there exist a path between s and t?
stCon(Graph graph, Vertex start, Vertex t) {
Queue<Vertex> perimeter = new Queue<>();
Set<Vertex> visited = new Set<>();
perimeter.add(start);
visited.add(start);
while (!perimeter.isEmpty()) {
Vertex from = perimeter.remove();
if (from == t) { return true; }
for (Edge edge : graph.edgesFrom(from)) {
Vertex to = edge.to();
if (!visited.contains(to)) {
perimeter.add(to);
visited.add(to);
}
}
}
return false;
}
Topological Sort
Topological Sort
A
B
C
A before C
B before C
A before B
A
B
C
Topological Sort:
With original edges for reference:
A
B
C
Input:
Problem 1: Ordering Dependencies
CSE 373 SP 18 - KASEY CHAMPION
29
Math 126
CSE 142
CSE 143
CSE 373
CSE 374
CSE 417
Ordering a DAG
CSE 373 19 WI - KASEY CHAMPION
30
A
B
C
E
D
If a vertex doesn’t have any edges going into it, we can add it to the ordering.
More generally, if the only incoming edges are from vertices already in the ordering, it’s safe to add.
0
1
2
1
1
A
C
B
D
E
0
1
0
0
0
Problem 1: Ordering Dependencies
CSE 373 19 SP - KASEY CHAMPION
31
Given: a directed graph G
Find: an ordering of the vertices so all edges go from left to right (all the dependency arrows are satisfied and the vertices can be processed left to right with no problems) .
Topological Sort (aka Topological Ordering)
Topological Ordering
CSE 373 19 SP - KASEY CHAMPION
32
Math 126
CSE 142
CSE 143
CSE 373
CSE 374
CSE 417
Math 126
CSE 142
CSE 143
CSE 373
CSE 374
CSE 417
Can We Always Topo Sort a Graph?
CSE 143
CSE 373
CSE 417
🤔 Where do I start?
Where do I end? 🤔
MATH 126
CSE 142
CSE 143
CSE 373
CSE 374
CSE 417
No 😭
DIRECTED ACYCLIC GRAPH
Topological Sort Pseudocode
CSE 373 SP 22 - KASEY CHAMPION
toposort(Graph graph) {
Queue<Vertex> perimeter = new Queue<>();
Set<Vertex> visited = new Set<>();
Map<Vertex, Integer> indegree = countInDegree(graph);
for (Vertex v : indegree.keySet()) {
if(indegree.get(v) == 0) {
perimeter.add(v);
visited.add(v);
}
}
while (!perimeter.isEmpty()) {
Vertex from = perimeter.remove();
for (Edge edge : graph.edgesFrom(from)) {
Vertex to = edge.to();
if (!visited.contains(to)) {
int inDeg = indegree.get(to);
inDeg--;
if (inDeg == 0) {
perimeter.add(to);
visited.add(to);
}
indegree.put(to, inDeg);
}...
Start with BFS code (Queue to visit neighbors, List to mark visited)
Count the in-degree of each vertex
queue up the 0 in-degree nodes to visit
Loop over Queue
for each neighbor of a visited node reduce their in-degree count
for nodes that hit 0, add them to Queue
Toposort is order nodes are “visited” (could create separate List to track order, could print out as you add to Set)
Shortest Path
CSE 373 SP 22 - KASEY CHAMPION
35
The Shortest Path Problem
(Unweighted) Shortest Path Problem
Given source vertex s and a target vertex t, how long is the shortest path from s to t? What edges make up that path?
Using BFS for the Shortest Path Problem
(Unweighted) Shortest Path Problem
Given source vertex s and a target vertex t, how long is the shortest path from s to t? What edges make up that path?
...
Map<Vertex, Edge> edgeTo = ...
Map<Vertex, Double> distTo = ...
edgeTo.put(start, null);
distTo.put(start, 0.0);
while (!perimeter.isEmpty()) {
Vertex from = perimeter.remove();
for (Edge edge : graph.edgesFrom(from)) {
Vertex to = edge.to();
if (!visited.contains(to)) {
edgeTo.put(to, edge);
distTo.put(to, distTo.get(from) + 1);
perimeter.add(to);
visited.add(to);
}
}
}
return edgeTo;
}
Remember how we got to this point, and what layer this vertex is part of
The start required no edge to arrive at, and is on level 0
BFS for Shortest Paths: Example
A
B
E
C
D
start
VISITED
PERIMETER
|
...
Map<Vertex, Edge> edgeTo = ...
Map<Vertex, Double> distTo = ...
edgeTo.put(start, null);
distTo.put(start, 0.0);
while (!perimeter.isEmpty()) {
Vertex from = perimeter.remove();
for (Edge edge : graph.edgesFrom(from)) {
Vertex to = edge.to();
if (!visited.contains(to)) {
edgeTo.put(to, edge);
distTo.put(to, distTo.get(from) + 1);
perimeter.add(to);
visited.add(to);
}
}
}
return edgeTo;
}
EDGETO
DISTTO
0
1
1
2
2
A
B
C
D
E
What about the Target Vertex?
A
B
E
C
D
start
EDGETO
DISTTO
0
1
1
2
2
Shortest Path Tree:
Recap: Graph Problems
EASY
MEDIUM
s-t Connectivity Problem
Given source vertex s and a target vertex t, does there exist a path between s and t?
(Unweighted) Shortest Path Problem
Given source vertex s and a target vertex t, how long is the shortest path from s to t? What edges make up that path?
BFS or DFS + check if we’ve hit t
BFS + generate shortest path tree as we go
What about the Shortest Path Problem on a weighted graph?
Next Stop Weighted Shortest Paths
HARDER (FOR NOW)
A
B
C
D
14.0
12.0
9000.2
1.5
start
target
Dijkstra’s Algorithm
Dijkstra’s Algorithm: Idea
A
B
D
C
F
H
E
G
2
2
3
1
10
2
3
1
11
7
1
9
2
4
5
0
4
2
1
4??
12??
∞
∞
KNOWN
UNKNOWN
PERIMETER
start
dijkstraShortestPath(G graph, V start)
�
Dijkstra’s Pseudocode (High-Level)
Similar to “visited” in BFS, “known” is nodes that are finalized (we know their path)
Dijkstra’s algorithm is all about updating “best-so-far” in distTo if we find shorter path! Init all paths to infinite.
Order matters: always visit closest first!
Consider all vertices reachable from me: would getting there through me be a shorter path than they currently know about?
C
D
B
A
KNOWN
PERIMETER
0
2
3
7??
2
3
5
1
start
u
v
Set known; Map edgeTo, distTo;
initialize distTo with all nodes mapped to ∞, except start to 0
while (there are unknown vertices):
let u be the closest unknown vertex
known.add(u);
for each edge (u,v) from u with weight w:
oldDist = distTo.get(v) // previous best path to v
newDist = distTo.get(u) + w // what if we went through u?
if (newDist < oldDist):
distTo.put(v, newDist)
edgeTo.put(v, u)
Dijkstra’s Algorithm: Key Properties
dijkstraShortestPath(G graph, V start)
Set known; Map edgeTo, distTo;
initialize distTo with all nodes mapped to ∞, except start to 0
while (there are unknown vertices):
let u be the closest unknown vertex
known.add(u)
for each edge (u,v) to unknown v with weight w:
oldDist = distTo.get(v) // previous best path to v
newDist = distTo.get(u) + w // what if we went through u?
if (newDist < oldDist):
distTo.put(v, newDist)
edgeTo.put(v, u)�
Dijkstra’s Algorithm: Example #1
46
Order Added to Known Set:
Vertex | Known? | distTo | edgeTo |
A | | ∞ | |
B | | ∞ | |
C | | ∞ | |
D | | ∞ | |
E | | ∞ | |
F | | ∞ | |
G | | ∞ | |
H | | ∞ | |
A
B
D
C
F
H
E
G
2
2
3
1
10
2
3
1
11
7
1
9
2
4
5
∞
∞
∞
∞
∞
∞
∞
0
start
Dijkstra’s Algorithm: Example #1
47
Order Added to Known Set:
A
Vertex | Known? | distTo | edgeTo |
A | Y | 0 | / |
B | | ≤ 2 | A |
C | | ≤ 1 | A |
D | | ≤ 4 | A |
E | | ∞ | |
F | | ∞ | |
G | | ∞ | |
H | | ∞ | |
A
B
D
C
F
H
E
G
2
2
3
1
10
2
3
1
11
7
1
9
2
4
5
2??
∞
∞
1??
4??
∞
∞
0
start
Dijkstra’s Algorithm: Example #1
48
Order Added to Known Set:
A, C
Vertex | Known? | distTo | edgeTo |
A | Y | 0 | / |
B | | ≤ 2 | A |
C | Y | 1 | A |
D | | ≤ 4 | A |
E | | ≤ 12 | C |
F | | ∞ | |
G | | ∞ | |
H | | ∞ | |
A
B
D
C
F
H
E
G
2
2
3
1
10
2
3
1
11
7
1
9
2
4
5
2??
∞
∞
1
4??
∞
12??
0
start
Dijkstra’s Algorithm: Example #1
49
Order Added to Known Set:
A, C, B
Vertex | Known? | distTo | edgeTo |
A | Y | 0 | / |
B | Y | 2 | A |
C | Y | 1 | A |
D | | ≤ 4 | A |
E | | ≤ 12 | C |
F | | ≤ 4 | B |
G | | ∞ | |
H | | ∞ | |
A
B
D
C
F
H
E
G
2
2
3
1
10
2
3
1
11
7
1
9
2
4
5
2
4??
∞
1
4??
∞
12??
0
start
Dijkstra’s Algorithm: Example #1
50
Order Added to Known Set:
A, C, B, D
Vertex | Known? | distTo | edgeTo |
A | Y | 0 | / |
B | Y | 2 | A |
C | Y | 1 | A |
D | Y | 4 | A |
E | | ≤ 12 | C |
F | | ≤ 4 | B |
G | | ∞ | |
H | | ∞ | |
A
B
D
C
F
H
E
G
2
2
3
1
10
2
3
1
11
7
1
9
2
4
5
2
4??
∞
1
4
∞
12??
0
start
Dijkstra’s Algorithm: Example #1
51
Order Added to Known Set:
A, C, B, D, F
Vertex | Known? | distTo | edgeTo |
A | Y | 0 | / |
B | Y | 2 | A |
C | Y | 1 | A |
D | Y | 4 | A |
E | | ≤ 12 | C |
F | Y | 4 | B |
G | | ∞ | |
H | | ≤ 7 | F |
A
B
D
C
F
H
E
G
2
2
3
1
10
2
3
1
11
7
1
9
2
4
5
2
4
7??
1
4
∞
12??
0
start
Dijkstra’s Algorithm: Example #1
52
Order Added to Known Set:
A, C, B, D, F, H
Vertex | Known? | distTo | edgeTo |
A | Y | 0 | / |
B | Y | 2 | A |
C | Y | 1 | A |
D | Y | 4 | A |
E | | ≤ 12 | C |
F | Y | 4 | B |
G | | ≤ 8 | H |
H | Y | 7 | F |
A
B
D
C
F
H
E
G
2
2
3
1
10
2
3
1
11
7
1
9
2
4
5
2
4
7
1
4
8??
12??
0
start
Dijkstra’s Algorithm: Example #1
53
Order Added to Known Set:
A, C, B, D, F, H, G
Vertex | Known? | distTo | edgeTo |
A | Y | 0 | / |
B | Y | 2 | A |
C | Y | 1 | A |
D | Y | 4 | A |
E | | ≤ 11 | G |
F | Y | 4 | B |
G | Y | 8 | H |
H | Y | 7 | F |
A
B
D
C
F
H
E
G
2
2
3
1
10
2
3
1
11
7
1
9
2
4
5
2
4
7
1
4
8
11??
0
start
Dijkstra’s Algorithm: Example #1
54
Order Added to Known Set:
A, C, B, D, F, H, G, E
Vertex | Known? | distTo | edgeTo |
A | Y | 0 | / |
B | Y | 2 | A |
C | Y | 1 | A |
D | Y | 4 | A |
E | Y | 11 | G |
F | Y | 4 | B |
G | Y | 8 | H |
H | Y | 7 | F |
A
B
D
C
F
H
E
G
2
2
3
1
10
2
3
1
11
7
1
9
2
4
5
2
4
7
1
4
8
11
0
start
Dijkstra’s Algorithm: Interpreting the Results
Now that we’re done, how do we get the path from A to E?
55
Order Added to Known Set:
A, C, B, D, F, H, G, E
Vertex | Known? | distTo | edgeTo |
A | Y | 0 | / |
B | Y | 2 | A |
C | Y | 1 | A |
D | Y | 4 | A |
E | Y | 11 | G |
F | Y | 4 | B |
G | Y | 8 | H |
H | Y | 7 | F |
A
B
D
C
F
H
E
G
2
2
3
1
10
2
3
1
11
7
1
9
2
4
5
2
4
7
1
4
8
11
0
start
Review: Key Features
Appendix
Graph problems
▪ What is the longest without cycles?
HANNAH TANG 20WI
Graph problems
HANNAH TANG 20WI
s-t path Problem
60
1
2
3
4
5
6
7
8
0
s
t
s-t path Problem
61
1
2
3
4
5
6
7
8
0
s
t
traversals are really important to solving this problem / problems in general, so slight detour to talk about them, we’ll come back to this though
Graph traversals: DFS
Kind of like wandering a maze – if you get stuck at a dead end (since you physically have to go and try it out to know it’s a dead end), trace your steps backwards towards your last decision and when you get back there, choose a different option than you did before.
one valid DFS traversal: 10, 5, 3, 2, 4, 8, 7,6, 9, 15, 12, 14, 18
Graph traversals: BFS
one valid BFS traversal: 10, 5, 15, 3, 8, 12, 18, 2, 4, 7, 9, 14, 6
Graph traversals: BFS and DFS on more graphs
In DFS, you go as far as you can down one path till you hit a dead end (no neighbors are still undiscovered or you have no neighbors). Once you hit a dead end, you backtrack / undo until you find some options/edges that you haven’t actually tried yet.
In BFS, you traverse level by level
Graph traversals: BFS and DFS on more graphs
In DFS, you go as far as you can down one path till you hit a dead end (no neighbors are still undiscovered or you have no neighbors). Once you hit a dead end, you backtrack / undo until you find some options/edges that you haven’t actually tried yet.
In BFS, you traverse level by level
Graph traversals: BFS and DFS on more graphs
https://visualgo.net/en/dfsbfs
BFS pseudocode (some details not Java specific)
1
2
3
4
5
6
7
8
0
s
t
BFS pseudocode (some details not Java specific)
1
2
3
4
5
6
7
8
0
s
t
Perimeter queue:
Discovered set:
Expected levels starting the BFS from 0:
DFS pseudocode (some details not Java specific)
1
2
3
4
5
6
7
8
0
s
t
Modifying BFS and DFS
BFS and DFS are like the for loops over arrays for graphs. They’re super fundamental to so many ideas, but when they’re by themselves they don’t do anything. Consider the following code:
for (int i = 0; i < n; i++) {
int x = arr[i];
}
We actually need to do something with the data for it to be useful!
A lot of times to solve basic graph problems (which show up in technical interviews at this level), and often the answer is that you just need to describe / implement BFS/DFS with a small modification for your specific problem.
Now back to the s-t path problem…
Modifying BFS for the s-t path problem
Questions / clarifications on anything?
we covered:
Roadmap for today
Shortest Path problem (unweighted graph)
1
2
4
5
6
7
8
0
s
t
Shortest Path problem (unweighted graph)
CSE 373 19 SU - ROBBIE WEBER
76
1
2
4
5
6
7
8
0
s
t
Shortest Path problem (unweighted graph) key idea
CSE 373 19 SU - ROBBIE WEBER
77
perimeter.add(start);
discovered.add(start);
start.distance = 0;
while (!perimeter.isEmpty()) {
Vertex from = perimeter.remove();
for (E edge : graph.outgoingEdgesFrom(from)) {
Vertex to = edge.to();
if (!discovered.contains(to)) {
to.distance = from.distance + 1;
to.predecessorEdge = edge;
perimeter.add(to);
discovered.add(to)
}
}
}
Changes from traversal BFS:
Unweighted Graphs
CSE 373 19 SU - ROBBIE WEBER
perimeter.add(start);
discovered.add(start);
start.distance = 0;
while (!perimeter.isEmpty()) {
Vertex from = perimeter.remove();
for (E edge : graph.outgoingEdgesFrom(from)) {
Vertex to = edge.to();
if (!discovered.contains(to)) {
to.distance = from.distance + 1;
to.predecessorEdge = edge;
perimeter.add(to);
discovered.add(to)
}
}
}
1
2
4
5
6
7
8
0
s
t
Unweighted Graphs
CSE 373 19 SU - ROBBIE WEBER
79
1
2
4
5
6
7
8
0
s
t
perimeter.add(start);
discovered.add(start);
start.distance = 0;
while (!perimeter.isEmpty()) {
Vertex from = perimeter.remove();
for (E edge : graph.outgoingEdgesFrom(from)) {
Vertex to = edge.to();
if (!discovered.contains(to)) {
to.distance = from.distance + 1;
to.predecessorEdge = edge;
perimeter.add(to);
discovered.add(to)
}
}
}
If trying to recall the best path from 0 to 5:
5’s predecessor edge is (8, 5)
8’s predecessor edge is (0, 8)
0 was the start vertex
Note: this BFS modification produces these edges, but there’s extra work to figure out a specific path from a start / target
What about the target vertex?
CSE 373 19 SU - ROBBIE WEBER
80
Given: a directed graph G and vertices s,t
Find: the shortest path from s to t.
Shortest Path Problem
BFS didn’t mention a target vertex…
It actually finds the distance from s to every other vertex. The resulting edges are called the shortest path tree.
All our shortest path algorithms have this property.
If you only care about one target, you can sometimes stop early (in bfsShortestPaths, when the target pops off the queue)
Map<V, E> bfsFindShortestPathsEdges(G graph, V start) {
// stores the edge `E` that connects `V` in the shortest path from s to V
Set<V> discovered = new Set<>();
1
2
4
5
6
7
8
0
s
t
This is an alternative way to implement bfsShortestPaths that has an easier time accessing the actual paths / distances by using Maps