# 图之DFS、BFS、Dijkstra、Floyd、Prim、Kruskal算法

## DFS和BFS

graph = {
'a' : ['b', 'c'],
'b' : ['a', 'c', 'd'],
'c' : ['a','b', 'd','e'],
'd' : ['b' , 'c', 'e', 'f'],
'e' : ['c', 'd'],
'f' : ['d']
}

def dfs(graph, s):
stack = []
stack.append(s)
visited = set()
while len(stack) > 0:
vertex = stack.pop()
nodes = graph[vertex]
for node in nodes:
if node not in visited:
stack.append(node)
print(vertex)
dfs(graph, 'a')
## 运行结果
a
c
e
d
f
b

def bfs(graph, s):
queue = []
queue.append(s)
visited = set()
while len(queue) > 0:
vertex = queue.pop(0)
nodes = graph[vertex]
for node in nodes:
if node not in visited:
queue.append(node)
print(vertex)
bfs(graph, 'a')
## 运行结果
a
b
c
d
e
f


## 最短路径算法：Dijkstra、Floyd算法

inf = float('inf')
matrix_distance = [[0,1,12,inf,inf,inf],
[inf,0,9,3,inf,inf],
[inf,inf,0,inf,5,inf],
[inf,inf,4,0,13,15],
[inf,inf,inf,inf,0,4],
[inf,inf,inf,inf,inf,0]]


### Dijkstra算法

Dijkstra算法是求从某个源点到其余各个顶点的最短路径（单源最短路径），时间复杂度为 O(n^2) ，主要思想为每次在未确定的顶点中选取最短的路径，并把最短路径的顶点设为确定值，然后再由源点经该点出发来松弛其他顶点的路径的值，重复以上步骤最后得到就是最短路径了。

def dijkstra(matrix_dist, src_node):
inf = float('inf')
# init the source node distance to others
dists = matrix_dist[src_node]
node_nums = len(dists)
flag = [0] * node_nums
flag[src_node] = 1
for i in range(node_nums - 1):
mini = inf
# find the min node from the source node
for j in range(node_nums):
if flag[j] == 0 and dists[j] < mini:
mini = dists[j]
u = j
flag[u] = 1
# update the dis
for v in range(node_nums):
if flag[v] == 0 and matrix_dist[u][v] < inf:
if dists[v] > dists[u] + matrix_dist[u][v]:
dists[v] = dists[u] + matrix_dist[u][v]
return dists
print(dijkstra(matrix_distance, 0))
## 运行结果
[0, 1, 8, 4, 13, 17]


### Floyd算法

Floyd算法针对的问题是求每对顶点之间的最短路径，相当于把Dijkstra算法执行了n遍（实际上并不是这样做），所以Floyd算法的时间复杂度为 O(n^3),主要用公式：

def floyd(dis):
# min (Dis(i,j) , Dis(i,k) + Dis(k,j) )
num_vertex = len(dis[0])
for k in range(num_vertex):
for i in range(num_vertex):
for j in range(num_vertex):
if dis[i][j] > dis[i][k] + dis[k][j]:
dis[i][j] = dis[i][k] + dis[k][j]
return dis
print(floyd(matrix_distance))


## 最小代价生成树：Prim、Kruskal算法

### Prim算法

Prim算法是从任意一个顶点开始，每次选择一个与当前顶点集最近的一个顶点，并将两顶点之间的边加入到树中，其实就是说在当前顶点集所可以辐射到的边中选择最小的一条边（需要判断该边是否已经在最小生成树中），其实就是一个排序问题，然后贪心选取最小值。
Prim算法的时间复杂度为O(n^2) ，n表示顶点数目，这跟它的初心还是蛮符合的，毕竟它是从顶点出发，可以从公式中看出Prim算法的时间复杂度与网络中的边无关，所以适合来求解边稠密的网的最小代价生成树.

from collections import defaultdict
from heapq import *

def Prim(vertexs, edges, start_node):
for v1, v2, length in edges:

mst = []
closed = set(start_node)

if v2 not in closed:
mst.append((v1, v2, w))

if next_vertex[2] not in closed:

return mst

vertexs = list("ABCDEFG")
edges = [ ("A", "B", 7), ("A", "D", 5),
("B", "C", 8), ("B", "D", 9),
("B", "E", 7), ("C", "E", 5),
("D", "E", 15), ("D", "F", 6),
("E", "F", 8), ("E", "G", 9),
("F", "G", 11)]

print('prim:', Prim(vertexs, edges, 'A'))


### Kruskal算法

Kruskal算法选择从边开始，把所有的边按照权值先从小到大排列，接着按照顺序选取每条边（贪心思想），如果这条边的两个端点不属于同一集合，那么就将它们合并，直到所有的点都属于同一个集合为止，其实就是基于并查集的贪心算法。
Kruskal算适合来求边稀疏的网的最小代价生成树时间复杂度为 O(eloge)，e表示网络中的边数。

node = dict()
rank = dict()

def make_set(point):
node[point] = point
rank[point] = 0

def find(point):
if node[point] != point:
node[point] = find(node[point])
return node[point]

def merge(point1, point2):
root1 = find(point1)
root2 = find(point2)
if root1 != root2:
if rank[root1] > rank[root2]:
node[root2] = root1
else:
node[root1] = root2
if rank[root1] == rank[root2] : rank[root2] += 1

def Kruskal(graph):
for vertice in graph['vertices']:
make_set(vertice)

mst = set()

edges = list(graph['edges'])
edges.sort()
for edge in edges:
weight, v1, v2 = edge
if find(v1) != find(v2):
merge(v1 , v2)
return mst

graph = {
'vertices': ['A', 'B', 'C', 'D'],
'edges': set([
(1, 'A', 'B'),
(5, 'A', 'C'),
(3, 'A', 'D'),
(4, 'B', 'C'),
(2, 'B', 'D'),
(1, 'C', 'D'),
])
}

print(Kruskal(graph))

• 点赞
• 评论
• 分享
x

海报分享

扫一扫，分享海报

• 收藏 1
• 打赏

打赏

专注于计算机视觉的AndyJiang

谢谢您的打赏，我会继续努力的

C币 余额
2C币 4C币 6C币 10C币 20C币 50C币
• 举报
• 一键三连

点赞Mark关注该博主, 随时了解TA的最新博文
08-09 434

02-16 166
05-22 3125
09-21 1万+
05-24 8845