Lecture13–Part01...
Transcript of Lecture13–Part01...
![Page 1: Lecture13–Part01 GraphSearchStrategiessierra.ucsd.edu/dsc40b-2020-sp/lectures/13-BFS-I/build/lecture.pdfTimeComplexity def full_bfs(graph): status = {node: 'undiscovered' for node](https://reader034.fdocuments.us/reader034/viewer/2022042315/5f0353487e708231d408a800/html5/thumbnails/1.jpg)
Lecture 13 – Part 01Graph Search Strategies
![Page 2: Lecture13–Part01 GraphSearchStrategiessierra.ucsd.edu/dsc40b-2020-sp/lectures/13-BFS-I/build/lecture.pdfTimeComplexity def full_bfs(graph): status = {node: 'undiscovered' for node](https://reader034.fdocuments.us/reader034/viewer/2022042315/5f0353487e708231d408a800/html5/thumbnails/2.jpg)
How do we:
▶ determine if there is a path between two nodes?
▶ check if graph is connected?
▶ count connected components?
![Page 3: Lecture13–Part01 GraphSearchStrategiessierra.ucsd.edu/dsc40b-2020-sp/lectures/13-BFS-I/build/lecture.pdfTimeComplexity def full_bfs(graph): status = {node: 'undiscovered' for node](https://reader034.fdocuments.us/reader034/viewer/2022042315/5f0353487e708231d408a800/html5/thumbnails/3.jpg)
Search Stategies
▶ A search strategy is a procedure for exploring agraph.
▶ Different strategies have different properties.
![Page 4: Lecture13–Part01 GraphSearchStrategiessierra.ucsd.edu/dsc40b-2020-sp/lectures/13-BFS-I/build/lecture.pdfTimeComplexity def full_bfs(graph): status = {node: 'undiscovered' for node](https://reader034.fdocuments.us/reader034/viewer/2022042315/5f0353487e708231d408a800/html5/thumbnails/4.jpg)
Node Statuses
At any point during a search, a node is in exactly oneof three states:▶ visited▶ pending (discovered, but not yet visited)▶ undiscovered
![Page 5: Lecture13–Part01 GraphSearchStrategiessierra.ucsd.edu/dsc40b-2020-sp/lectures/13-BFS-I/build/lecture.pdfTimeComplexity def full_bfs(graph): status = {node: 'undiscovered' for node](https://reader034.fdocuments.us/reader034/viewer/2022042315/5f0353487e708231d408a800/html5/thumbnails/5.jpg)
Rules
▶ At every step, next visited node chosen fromamong pending nodes.
▶ When a node is marked as visited, all of itsneighbors have been marked as pending.
![Page 6: Lecture13–Part01 GraphSearchStrategiessierra.ucsd.edu/dsc40b-2020-sp/lectures/13-BFS-I/build/lecture.pdfTimeComplexity def full_bfs(graph): status = {node: 'undiscovered' for node](https://reader034.fdocuments.us/reader034/viewer/2022042315/5f0353487e708231d408a800/html5/thumbnails/6.jpg)
Choosing the next Node
How to choose among pending nodes?▶ Visit newest pending (depth-first search).
▶ Visit oldest pending (breadth-first search).
![Page 7: Lecture13–Part01 GraphSearchStrategiessierra.ucsd.edu/dsc40b-2020-sp/lectures/13-BFS-I/build/lecture.pdfTimeComplexity def full_bfs(graph): status = {node: 'undiscovered' for node](https://reader034.fdocuments.us/reader034/viewer/2022042315/5f0353487e708231d408a800/html5/thumbnails/7.jpg)
Breadth-First Search
At every step:1. Visit oldest pending node.
2. Mark its undiscovered neighbors as pending.To store pending nodes, use a FIFO queue.
![Page 8: Lecture13–Part01 GraphSearchStrategiessierra.ucsd.edu/dsc40b-2020-sp/lectures/13-BFS-I/build/lecture.pdfTimeComplexity def full_bfs(graph): status = {node: 'undiscovered' for node](https://reader034.fdocuments.us/reader034/viewer/2022042315/5f0353487e708231d408a800/html5/thumbnails/8.jpg)
Queues in Python
▶ Want Θ(1) time pops/appends on either side.
▶ from collections import deque (“deck”).▶ .popleft() and .pop()▶ list doesn’t have right time complexity!▶ import queue isn’t what you want!
▶ Keep track of node status attribute usingdictionary.
![Page 9: Lecture13–Part01 GraphSearchStrategiessierra.ucsd.edu/dsc40b-2020-sp/lectures/13-BFS-I/build/lecture.pdfTimeComplexity def full_bfs(graph): status = {node: 'undiscovered' for node](https://reader034.fdocuments.us/reader034/viewer/2022042315/5f0353487e708231d408a800/html5/thumbnails/9.jpg)
BFSfrom collections import dequedef bfs(graph, source):
”””Start a BFS at `source`.”””status = {node: 'undiscovered' for node in graph.nodes}status[source] = 'pending'pending = deque([source])# while there are still pending nodeswhile pending:
u = pending.popleft()for v in graph.neighbors(u):
# explore edge (u,v)if status[v] == 'undiscovered':
status[v] = 'pending'# append to rightpending.append(v)
status[u] = 'visited'
![Page 10: Lecture13–Part01 GraphSearchStrategiessierra.ucsd.edu/dsc40b-2020-sp/lectures/13-BFS-I/build/lecture.pdfTimeComplexity def full_bfs(graph): status = {node: 'undiscovered' for node](https://reader034.fdocuments.us/reader034/viewer/2022042315/5f0353487e708231d408a800/html5/thumbnails/10.jpg)
Example
1
2
3
4
5
6
![Page 11: Lecture13–Part01 GraphSearchStrategiessierra.ucsd.edu/dsc40b-2020-sp/lectures/13-BFS-I/build/lecture.pdfTimeComplexity def full_bfs(graph): status = {node: 'undiscovered' for node](https://reader034.fdocuments.us/reader034/viewer/2022042315/5f0353487e708231d408a800/html5/thumbnails/11.jpg)
Example
1
2
3
4
5
6
pending = [1]
Before iterating.
![Page 12: Lecture13–Part01 GraphSearchStrategiessierra.ucsd.edu/dsc40b-2020-sp/lectures/13-BFS-I/build/lecture.pdfTimeComplexity def full_bfs(graph): status = {node: 'undiscovered' for node](https://reader034.fdocuments.us/reader034/viewer/2022042315/5f0353487e708231d408a800/html5/thumbnails/12.jpg)
Example
1
2
3
4
5
6
pending = [2,3,4]
After 1st iteration.
![Page 13: Lecture13–Part01 GraphSearchStrategiessierra.ucsd.edu/dsc40b-2020-sp/lectures/13-BFS-I/build/lecture.pdfTimeComplexity def full_bfs(graph): status = {node: 'undiscovered' for node](https://reader034.fdocuments.us/reader034/viewer/2022042315/5f0353487e708231d408a800/html5/thumbnails/13.jpg)
Example
1
2
3
4
5
6
pending = [3,4]
After 2nd iteration.
![Page 14: Lecture13–Part01 GraphSearchStrategiessierra.ucsd.edu/dsc40b-2020-sp/lectures/13-BFS-I/build/lecture.pdfTimeComplexity def full_bfs(graph): status = {node: 'undiscovered' for node](https://reader034.fdocuments.us/reader034/viewer/2022042315/5f0353487e708231d408a800/html5/thumbnails/14.jpg)
Example
1
2
3
4
5
6
pending = [4]
After 3rd iteration.
![Page 15: Lecture13–Part01 GraphSearchStrategiessierra.ucsd.edu/dsc40b-2020-sp/lectures/13-BFS-I/build/lecture.pdfTimeComplexity def full_bfs(graph): status = {node: 'undiscovered' for node](https://reader034.fdocuments.us/reader034/viewer/2022042315/5f0353487e708231d408a800/html5/thumbnails/15.jpg)
Example
1
2
3
4
5
6
pending = [6]
After 4th iteration.
![Page 16: Lecture13–Part01 GraphSearchStrategiessierra.ucsd.edu/dsc40b-2020-sp/lectures/13-BFS-I/build/lecture.pdfTimeComplexity def full_bfs(graph): status = {node: 'undiscovered' for node](https://reader034.fdocuments.us/reader034/viewer/2022042315/5f0353487e708231d408a800/html5/thumbnails/16.jpg)
Example
1
2
3
4
5
6
pending = [5]
After 5th iteration.
![Page 17: Lecture13–Part01 GraphSearchStrategiessierra.ucsd.edu/dsc40b-2020-sp/lectures/13-BFS-I/build/lecture.pdfTimeComplexity def full_bfs(graph): status = {node: 'undiscovered' for node](https://reader034.fdocuments.us/reader034/viewer/2022042315/5f0353487e708231d408a800/html5/thumbnails/17.jpg)
Example
1
2
3
4
5
6
pending = []
After 6th iteration.
![Page 18: Lecture13–Part01 GraphSearchStrategiessierra.ucsd.edu/dsc40b-2020-sp/lectures/13-BFS-I/build/lecture.pdfTimeComplexity def full_bfs(graph): status = {node: 'undiscovered' for node](https://reader034.fdocuments.us/reader034/viewer/2022042315/5f0353487e708231d408a800/html5/thumbnails/18.jpg)
Note
▶ BFS works just as well for directed graphs.
![Page 19: Lecture13–Part01 GraphSearchStrategiessierra.ucsd.edu/dsc40b-2020-sp/lectures/13-BFS-I/build/lecture.pdfTimeComplexity def full_bfs(graph): status = {node: 'undiscovered' for node](https://reader034.fdocuments.us/reader034/viewer/2022042315/5f0353487e708231d408a800/html5/thumbnails/19.jpg)
Claim
▶ bfs with source 𝑢 will visit all nodes reachablefrom 𝑢 (and only those nodes).
▶ Useful!▶ Is there a path between 𝑢 and 𝑣?▶ Is graph connected?
![Page 20: Lecture13–Part01 GraphSearchStrategiessierra.ucsd.edu/dsc40b-2020-sp/lectures/13-BFS-I/build/lecture.pdfTimeComplexity def full_bfs(graph): status = {node: 'undiscovered' for node](https://reader034.fdocuments.us/reader034/viewer/2022042315/5f0353487e708231d408a800/html5/thumbnails/20.jpg)
Lecture 13 – Part 02Analysis of BFS
![Page 21: Lecture13–Part01 GraphSearchStrategiessierra.ucsd.edu/dsc40b-2020-sp/lectures/13-BFS-I/build/lecture.pdfTimeComplexity def full_bfs(graph): status = {node: 'undiscovered' for node](https://reader034.fdocuments.us/reader034/viewer/2022042315/5f0353487e708231d408a800/html5/thumbnails/21.jpg)
Exploring with BFS
▶ BFS will visit all nodes reachable from source.
▶ If disconnected, BFS will not visit all nodes.
▶ We can do so with a full BFS.▶ Idea: “re-start” BFS on undiscovered node.▶ Must pass statuses between calls.
![Page 22: Lecture13–Part01 GraphSearchStrategiessierra.ucsd.edu/dsc40b-2020-sp/lectures/13-BFS-I/build/lecture.pdfTimeComplexity def full_bfs(graph): status = {node: 'undiscovered' for node](https://reader034.fdocuments.us/reader034/viewer/2022042315/5f0353487e708231d408a800/html5/thumbnails/22.jpg)
Making Full BFS
Modify bfs to accept statuses:
def bfs(graph, source, status=None):”””Start a BFS at `source`.”””if status is None:
status = {node: 'undiscovered' for node in graph.nodes}# ...
![Page 23: Lecture13–Part01 GraphSearchStrategiessierra.ucsd.edu/dsc40b-2020-sp/lectures/13-BFS-I/build/lecture.pdfTimeComplexity def full_bfs(graph): status = {node: 'undiscovered' for node](https://reader034.fdocuments.us/reader034/viewer/2022042315/5f0353487e708231d408a800/html5/thumbnails/23.jpg)
Making Full BFS
Call bfs multiple times:def full_bfs(graph):
status = {node: 'undiscovered' for node in graph.nodes}for node in graph.nodes:
if status[node] == 'undiscovered'bfs(graph, node, status)
![Page 24: Lecture13–Part01 GraphSearchStrategiessierra.ucsd.edu/dsc40b-2020-sp/lectures/13-BFS-I/build/lecture.pdfTimeComplexity def full_bfs(graph): status = {node: 'undiscovered' for node](https://reader034.fdocuments.us/reader034/viewer/2022042315/5f0353487e708231d408a800/html5/thumbnails/24.jpg)
Example
![Page 25: Lecture13–Part01 GraphSearchStrategiessierra.ucsd.edu/dsc40b-2020-sp/lectures/13-BFS-I/build/lecture.pdfTimeComplexity def full_bfs(graph): status = {node: 'undiscovered' for node](https://reader034.fdocuments.us/reader034/viewer/2022042315/5f0353487e708231d408a800/html5/thumbnails/25.jpg)
Observation
▶ If there are 𝑘 connected components, bfs in line5 is called exactly 𝑘 times.
1 def full_bfs(graph):2 status = {node: 'undiscovered' for node in graph.nodes}3 for node in graph.nodes:4 if status[node] == 'undiscovered'5 bfs(graph, node, status)
![Page 26: Lecture13–Part01 GraphSearchStrategiessierra.ucsd.edu/dsc40b-2020-sp/lectures/13-BFS-I/build/lecture.pdfTimeComplexity def full_bfs(graph): status = {node: 'undiscovered' for node](https://reader034.fdocuments.us/reader034/viewer/2022042315/5f0353487e708231d408a800/html5/thumbnails/26.jpg)
Key Properties of full_bfs
▶ Each node added to queue exactly once.
▶ Each edge is explored exactly:▶ once if graph is directed.▶ twice if graph is undirected.
![Page 27: Lecture13–Part01 GraphSearchStrategiessierra.ucsd.edu/dsc40b-2020-sp/lectures/13-BFS-I/build/lecture.pdfTimeComplexity def full_bfs(graph): status = {node: 'undiscovered' for node](https://reader034.fdocuments.us/reader034/viewer/2022042315/5f0353487e708231d408a800/html5/thumbnails/27.jpg)
Time Complexity of full_bfs
▶ Analyzing full_bfs is easier than analyzing bfs.▶ full_bfs visits all nodes, no matter the graph.
▶ Result will be upper bound on time complexityof bfs.
▶ We’ll use a aggregate analysis.
![Page 28: Lecture13–Part01 GraphSearchStrategiessierra.ucsd.edu/dsc40b-2020-sp/lectures/13-BFS-I/build/lecture.pdfTimeComplexity def full_bfs(graph): status = {node: 'undiscovered' for node](https://reader034.fdocuments.us/reader034/viewer/2022042315/5f0353487e708231d408a800/html5/thumbnails/28.jpg)
BFSfrom collections import deque
def bfs(graph, source):”””Start a BFS at `source`.”””status = {node: 'undiscovered' for node in graph.nodes}
status[source] = 'pending'pending = deque([source])
# while there are still pending nodeswhile pending:
u = pending.popleft()for v in graph.neighbors(u):
# explore edge (u,v)if status[v] == 'undiscovered':
status[v] = 'pending'# append to rightpending.append(v)
status[u] = 'visited'
![Page 29: Lecture13–Part01 GraphSearchStrategiessierra.ucsd.edu/dsc40b-2020-sp/lectures/13-BFS-I/build/lecture.pdfTimeComplexity def full_bfs(graph): status = {node: 'undiscovered' for node](https://reader034.fdocuments.us/reader034/viewer/2022042315/5f0353487e708231d408a800/html5/thumbnails/29.jpg)
Time Complexitydef full_bfs(graph):
status = {node: 'undiscovered' for node in graph.nodes}for node in graph.nodes:
if status[node] == 'undiscovered'bfs(graph, node, status)
def bfs(graph, source):”””Start a BFS at `source`.”””status = {node: 'undiscovered' for node in graph.nodes}
status[source] = 'pending'pending = deque([source])
# while there are still pending nodeswhile pending:
u = pending.popleft()for v in graph.neighbors(u):
# explore edge (u,v)if status[v] == 'undiscovered':
status[v] = 'pending'# append to rightpending.append(v)
status[u] = 'visited'
![Page 30: Lecture13–Part01 GraphSearchStrategiessierra.ucsd.edu/dsc40b-2020-sp/lectures/13-BFS-I/build/lecture.pdfTimeComplexity def full_bfs(graph): status = {node: 'undiscovered' for node](https://reader034.fdocuments.us/reader034/viewer/2022042315/5f0353487e708231d408a800/html5/thumbnails/30.jpg)
Time Complexity of Full BFS
▶ Θ(𝑉 + 𝐸)
▶ If |𝑉| > |𝐸|: Θ(𝑉)
▶ If |𝑉| < |𝐸|: Θ(𝐸)
▶ Namely, if graph is complete: Θ(𝑉2).
▶ Namely, if graph is very sparse: Θ(𝑉).
![Page 31: Lecture13–Part01 GraphSearchStrategiessierra.ucsd.edu/dsc40b-2020-sp/lectures/13-BFS-I/build/lecture.pdfTimeComplexity def full_bfs(graph): status = {node: 'undiscovered' for node](https://reader034.fdocuments.us/reader034/viewer/2022042315/5f0353487e708231d408a800/html5/thumbnails/31.jpg)
Next Time
▶ Finding shortest paths using BFS.