1.图的广度遍历
二叉树的层序遍历,本质上也可以认为是深度优先遍历。
在图中,我们首先探索景点0的相邻景点1、2、3、4
接着,我们探索与景点0相隔一层的景点7、9、5、6:
最后,我们探索与景点0相隔两层的景点8、10:
2.图的BFS原理
广度遍历我觉得理解起来更简单,就是一层一层的进行遍历,比如说以0顶点开始,0往下指向1,3,4,遍历的时候就先遍历0,然后再遍历它下一层的1,3,4------>然后分别遍历1,3,4的下一层---->而1,3,4只有1有下一层,则遍历1的下一层5,同理最后遍历2
即广度优先遍历得到的遍历结果应为:0 1 3 4 5 2
和二叉树的层序遍历一样,图的广度遍历也用到了队列,对于下图而言,先将0放入队首----->然后遍历0并将0从队列中取出,同时将0的邻接点1,3,4入队,这样队首就是1----->然后将1出队,并将1的邻接点入队(这里只有5), 这样队首就是3----->然后将3弹出并将3的邻接点入队(这里没有),这样队首就是4----->然后将4弹出并将4的邻接点入队(这里没有),队首就是从1入队的1的第一个邻接点(这里是5)---->然后将5弹出----->直到队列为空这样就完成了由定点0开始的广度优先遍历
3.python队列实现BFS
bfs总是先访问完同一层的结点,然后才继续访问下一层结点,它最有用的性质是可以遍历一次就生成中心结点到所遍历结点的最短路径,这一点在求无权图的最短路径时非常有用。广度优先遍历的核心思想非常简单,用python实现起来也就十来行代码。下面就是超精简的实现,用来理解核心思想足够了:
import Queue
def bfs(adj, start):
visited = set()
q = Queue.Queue()
q.put(start)
while not q.empty():
u = q.get()
print(u)
for v in adj.get(u, []):
if v not in visited:
visited.add(v)
q.put(v)
graph = {1: [4, 2], 2: [3, 4], 3: [4], 4: [5]}
bfs(graph, 1)
1 创建一个队列,遍历的起始点放入队列
2 从队列中取出一个元素,打印它,并将其未访问过的子结点放到队列中
3 重复2,直至队列空
时间复杂度:基本与图的规模成线性关系了,比起图的其它算法动不动就O(n^2)的复杂度它算是相当良心了
空间复杂度:我们看到程序中使用了一个队列,这个队列会在保存一层的结点,当图规模很大时占用内存还是相当可观的了,所以一般会加上一些条件,比如遍历到第N层就停止。
4.迷宫的最短路径(python实现)
# 给定一个大小为N*M的迷宫,由通道('.')和墙壁('#')组成,其中通道S表示起点,通道G表示终点,
# 每一步移动可以达到上下左右中不是墙壁的位置。试求出起点到终点的最小步数。(本题假定迷宫是有解的)(N,M<=100)
# 样例输入:
# 10 10
# #S######.#
# ......#..#
# .#.##.##.#
# .#........
# ##.##.####
# ....#....#
# .#######.#
# ....#.....
# .####.###.
# ....#...G#
#样例输出:
# 22
# 本解答也输出了最短路径的轨迹(之一)
from collections import deque
MAX_VALUE = 0x7fffffff
class Point:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def bfs(maze, begin, end):
n, m = len(maze), len(maze[0])
dist = [[MAX_VALUE for _ in range(m)] for _ in range(n)]
pre = [[None for _ in range(m)] for _ in range(n)] # 当前点的上一个点,用于输出路径轨迹
dx = [1, 0, -1, 0] # 四个方位
dy = [0, 1, 0, -1]
sx, sy = begin.x, begin.y
gx, gy = end.x, end.y
dist[sx][sy] = 0
queue = deque()
queue.append(begin)
while queue:
curr = queue.popleft()
find = False
for i in range(4):
nx, ny = curr.x + dx[i], curr.y + dy[i]
if 0<=nx<n and 0<=ny<m and maze[nx][ny] != '#' and dist[nx][ny] == MAX_VALUE:
dist[nx][ny] = dist[curr.x][curr.y] + 1
pre[nx][ny] = curr
queue.append(Point(nx, ny))
if nx == gx and ny == gy:
find = True
break
if find:
break
print('最短路径的长度:')
print(dist[gx][gy])
print('最短路径轨迹(之一):')
stack = []
curr = end
while True:
stack.append(curr)
if curr.x == begin.x and curr.y == begin.y:
break
prev = pre[curr.x][curr.y]
curr = prev
while stack:
curr = stack.pop()
print('(%d, %d)' % (curr.x, curr.y))
if __name__ == '__main__':
n, m = map(int, input().split())
maze = [['' for _ in range(m)] for _ in range(n)]
begin = Point()
end = Point()
for i in range(n):
s = input()
maze[i] = list(s)
if 'S' in s:
begin.x = i
begin.y = s.index('S')
if 'G' in s:
end.x = i
end.y = s.index('G')
bfs(maze, begin, end)