对于深度优先搜索(DFS)、广度优先搜索(BFS)的代码实现一直都有困惑,今天看了相关算法的讲解,用python来实现一下BFS和DFS,并进行扩展,包括使用BFS对无权无向图求解最短路径,以及对带权无向图求解最短路径的Dijkstra算法(BFS的扩展)进行解读。
BFS与DFS基础
重点:对于BFS,使用队列queue来存储待访问的节点;对于DFS,使用栈stack来存储待访问的节点;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 graph = { "A" : ["B" ,"C" ], "B" : ["A" ,"C" ,"D" ], "C" : ["A" ,"B" ,"D" ,"E" ], "D" : ["B" ,"C" ,"E" ,"F" ], "E" : ["C" ,"D" ], "F" : ["D" ] } def (graph,s) : queue = [] seen = set() queue.append(s) seen.add(s) while len(queue)>0 : vertex = queue.pop(0 ) nodes = graph[vertex] for w in nodes: if w not in seen: queue.append(w) seen.add(w) print(vertex) def DFS (graph,s) : stack = [] seen = set() stack.append(s) seen.add(s) while len(stack)>0 : vertex = stack.pop() nodes = graph[vertex] for w in nodes: if w not in seen: stack.append(w) seen.add(w) print(vertex) BFS(graph,"A" ) print('n' ) DFS(graph,"A" )
无权无向图求解最短路径 使用BFS的思想,求每个节点的上一个节点所构成的parent字典,然后从终点往前搜索,直到起点位置,从而得到最终的最短路径。
分析:为什么基于BFS可以求解这个问题?因为当前图为无权图,所以要求起点到终点的最短路径,即起点到终点每走一步则跨过一层。因此我们的目标是去判断每个节点属于第几层。而BFS的思想就是一层一层的遍历图。而且每个节点都与上面一层的一个和几个节点连接,在BFS中访问过的节点就不重新访问,所以最终遍历时每个节点只有一个上层直接相连的节点,因此我们可以用dict来存储每个节点的上层节点,保存为parent,如果终点为“E”,则其上一个节点即为上一层,以此往上推,则可以达到起点,这种方式能够保证每次走一层,而不会在同一层走多次导致最终的结果不是最短路径。这就是BFS所隐含的效果。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 graph = { "A" : ["B" ,"C" ], "B" : ["A" ,"C" ,"D" ], "C" : ["A" ,"B" ,"D" ,"E" ], "D" : ["B" ,"C" 大专栏 BFS和DFS相关知识汇总 ,"E" ,"F" ], "E" : ["C" ,"D" ], "F" : ["D" ] } def shortest_path (graph,s) : queue = [] seen = set() queue.append(s) seen.add(s) parent = {s:None } while len(queue)>0 : vertex = queue.pop(0 ) nodes = graph[vertex] for w in nodes: if w not in seen: queue.append(w) seen.add(w) parent[w] = vertex return parent parent = shortest_path(graph,"A" ) for w in parent.keys(): print(w,parent[w]) print('n' ) w = "E" while w!=None : print(w) w = parent[w]
带权无向图求解最短路径(Dijkstra) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 import heapqimport mathgraph = { "A" : {"B" : 5 , "C" : 1 }, "B" : {"A" : 5 , "C" : 2 , "D" : 1 }, "C" : {"A" : 1 , "B" : 2 , "D" : 4 , "E" : 8 }, "D" : {"B" : 1 , "C" : 4 , "E" : 3 , "F" : 6 }, "E" : {"C" : 8 , "D" : 3 }, "F" : {"D" : 6 } } def init_distance (graph, s) : distance = {s: 0 } for vertex in graph: if vertex != s: distance[vertex] = math.inf return distance def Dijkstra (graph, s) : pqueue = [] seen = set() heapq.heappush(pqueue, (0 , s)) parent = {s: None } distance = init_distance(graph, s) while len(pqueue) > 0 : pair = heapq.heappop(pqueue) dist = pair[0 ] vertex = pair[1 ] seen.add(vertex) nodes = graph[vertex].keys() for w in nodes: if w not in seen: if dist + graph[vertex][w] < distance[w]: heapq.heappush(pqueue, (dist + graph[vertex][w], w)) parent[w] = vertex distance[w] = dist + graph[vertex][w] return parent, distance parent, distance = Dijkstra(graph, "A" ) print(parent) print(distance)