Graph Algorithm: Breadth First Search

advertisement
Nattee Niparnan
GRAPH ALGORITHM:
BREADTH FIRST SEARCH
Distance of nodes
 The distance between two nodes is the
length of the shortest path between them
SA 1
SC 1
SB 2
DFS and Length
 DFS finds all nodes reachable from the
starting node
 But it might not be “visited” according to the
distance
Ball and Strings
We can compute distance by
proceeding from “layer” to “layer”
Shortest Path Problem (Undi,
Unit)
 Input:
 A graph, undirected
 A starting node S
 Output:
 A label on every node, giving the distance from S
to that node
Breadth-First-Search
 Visit node according to its layer
procedure bfs(G; s)
//Input: Graph G = (V,E), directed or undirected; vertex s  V
//Output: visit[u] is set to true for all nodes u reachable from v
for all u  V :
visit[u] = false
visit[s] = true
Queue Q = [s] (queue containing just s)
while Q is not empty:
u = eject(Q)
previsit(u)
visit[u] = true;
for all edges (u,v)  E:
if visit[v] = false:
visit[v] = true;
inject(Q,v);
postvisit(u)
Distance using BFS
procedure shortest_bfs(G, s)
//Input: Graph G = (V,E), directed or undirected; vertex s  V
//Output: For all vertices u reachable from s, dist(u) is set
to the distance from s to u.
for all u  V :
dist[u] = -1
dist[s] = 0
Queue Q = [s] (queue containing just s)
while Q is not empty:
u = eject(Q);
for all edges (u,v)  E:
if dist[v] = -1:
inject(Q,v);
dist[v] = dist[u] + 1;
Use dist as visit
DFS by Stack
procedure dfs(G, s)
//Input: Graph G = (V,E), directed or undirected; vertex s  V
//Output: visit[u] is set to true for all nodes u reachable from v
for all u  V :
visit[u] = false
visit[s] = true
Stack S = [s] (queue containing just s)
while S is not empty:
u = pop(S)
previsit(u)
for all edges (u,v)  E:
if visit [v] = false:
push(S,v)
visit[v] = true;
postvisit(u)
DFS vs BFS
 DFS goes depth first
 Trying to go further if possible
 Backtrack only when no other possible way to go
 Using Stack
 BFS goes breadth first
 Trying to visit node by the distance from the
starting node
 Using Queue
Graph with Length
Dijkstra’s Algorithm
Edge with Length
Length function
l(a,b) = distance
from a to b
Finding Shortest Path
 BFS can give us the shortest path
 Just convert the length edge into unit edge
However, this is very slow
Imagine a case when the length is 1,000,000
Alarm Clock Analogy
 No need to walk to every node
 Since it won’t change
anything
 We skip to the “actual” node
 Set up the clock at alarm at the
target node
Alarm Clock Algorithm
 Set an alarm clock for node s at time 0.
 Repeat until there are no more alarms:
 Say the next alarm goes off at time T, for node u.
Then:
 The distance from s to u is T.
 For each neighbor v of u in G:
 If there is no alarm yet for v, set one for time T + l(u, v).
 If v's alarm is set for later than T + l(u, v), then reset it to
this earlier time.
Dijkstra’s Algo from BFS
procedure dijkstra(G, l, s)
//Input: Graph G = (V;E), directed or undirected; vertex s  V;
positive edge lengths l
// Output: For all vertices u reachable from s, dist[u] is set
to the distance from s to u.
for all u  V :
dist[u] = +
prev(u) = nil
dist[s] = 0
H = makequeue(V) (using dist-values as keys)
while H is not empty:
u = deletemin(H)
for all edges (u; v)  E:
if dist[v] > dist[u] + l(u, v):
dist[v] = dist[u] + l(u, v)
prev[v] = u
decreasekey(H, v)
Another Implementation of
Dijkstra’s
 Growing from Known Region of shortest path
 Given a graph and a starting node s
 What if we know a shortest path from s to some
subset S’  V?
 Divide and Conquer Approach?
Dijktra’s Algo #2
procedure dijkstra(G, l, s)
//Input: Graph G = (V;E), directed or undirected; vertex s  V;
positive edge lengths l
// Output: For all vertices u reachable from s, dist[u] is set
to the distance from s to u.
for all u  V :
dist[u] = +
prev(u) = nil
dist[s] = 0
R = {}
// (the “known region”)
while R ≠ V :
Pick the node v  R with smallest dist[]
Add v to R
for all edges (v,z)  E:
if dist[z] > dist[v] + l(v,z):
dist[z] = dist[v] + l(v,z)
Analysis
 There are |V| ExtractMin
 Need to check all edges
 At most |E|, if we use adjacency list
 Maybe |V2|, if we use adjacency matrix
 Value of dist[] might be changed
 Depends on underlying data structure
Choice of DS
 Using simple array
 Each ExtractMin uses O(V)
 Each change of dist[] uses O(1)
 Result = O(V2 + E) = O(V2)
 Using binary heap
Might be V2
 Each ExtractMin uses O(lg V)
 Each change of dist[] uses O(lg V)
 Result = O( (V + E) lg V)
 Can be O (V2 lg V)
Good when
the graph is
sparse
Fibonacci Heap
 Using simple array
 Each ExtractMin uses O( lg V) (amortized)
 Each change of dist[] uses O(1) (amortized)
 Result = O(V lg V + E)
Graph with Negative Edge
 Disjktra’s works because a shortest path to v
must pass throught a node closer than v
 Shortest path to A pass through B which is…
in BFS sense… is further than A
Negative Cycle
 A graph with a negative cycle has no shortest
path
 The shortest.. makes no sense..
 Hence, negative edge must be a directed
Key Idea in Shortest Path
 Update the distance
if dist[z] > dist[v] + l(v,z):
dist[z] = dist[v] + l(v,z)
 This is safe to perform
 now, a shortest path must has at most |V| - 1
edges
Bellman-Ford Algorithm
procedure BellmanFord(G, l, s)
//Input: Graph G = (V;E), directed; vertex s  V; edge lengths l
(may be negative), no negative cycle
// Output: For all vertices u reachable from s, dist[u] is set
to the distance from s to u.
for all u  V :
dist[u] = +
prev(u) = nil
dist[s] = 0
repeat |V| - 1 times:
for all edges (a,b)  E:
if dist[b] > dist[a] + l(a,b):
dist[b] = dist[a] + l(a,b)
Shortest Path in DAG
 Path in DAG appears in linearized order
procedure dag-shortest-path(G, l, s)
//Input: DAG G = (V;E), vertex s  V; edge lengths l (may be
negative)
// Output: For all vertices u reachable from s, dist[u] is set
to the distance from s to u.
for all u  V :
dist[u] = +
prev(u) = nil
dist[s] = 0
Linearize G
For each u  V , in linearized order:
for all edges (u,v)  E:
if dist[v] > dist[u] + l(u,v):
dist[v] = dist[u] + l(y,v)
Download