图的表示
邻接矩阵
n*n的矩阵,有边是1,无边是0
1 | a, b, c, d, e, f, g, h = range(8) |
关于邻接矩阵:
- 主对角线为自己到自己,为0
- 行和为出度
- 列和为入度
邻接表
为每个点建立一个链表(数组)存放与之连接点1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17a, b, c, d, e, f, g, h = range(8)
N = [
{b, c, d, e, f},
{c, e},
{d},
{e},
{f},
{c, g, h},
{f, h},
{f, g}
]
# N(v) 代表的是 v 的邻居节点集;
in N[a] # neighborhood membership b
True
# out-degree:出度 len(N[f])
3
加权邻接表
使用 dict 类型来代替 set 或 list 来表示邻接集。在 dict 类型中,每个邻居节点都会有一个键和一个额外的值,用于表示与其邻居节点(或出边)之间的关联性,如边的权重。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18a, b, c, d, e, f, g, h = range(8)
N = [
{b:2, c:1, d:3, e:9, f:4},
{c:4, e:4},
{d:8},
{e:7},
{f:5},
{c:2, g:2, h:2},
{f:1, h:6},
{f:9, g:8}
]
in N[a] # neighborhood membership b
True
# out-degree len(N[f])
3
# Edge weight for (a, b) N[a][b]
2
图的实现
有下面一张图:
A -> B
A -> C
B -> C
B -> D
C -> D
D -> C
E -> F
F -> C
可以用字典和列表来构建graph = {'A': ['B', 'C'],'B': ['C', 'D'],'C': ['D'],'D': ['C'],'E': ['F'],'F': ['C']}
找到一条路径
1 | def find_path(graph, start, end, path=[]): |
找到所有路径
1 | def find_all_paths(graph, start, end, path=[]): |
找到最短路径
1 | def find_shortest_path(graph, start, end, path=[]): |
图的搜索
广度优先搜索
BFS算法框架
广(宽)度优先搜索(Breadth-First-Search)过程:
- 给定起点a,将a放入缓冲区,开始搜索
- 假定某时刻缓冲区结点为abc,则访问结点a的邻接点a1a2a3,同时缓冲区变为bca1a2a3
- 需要队列做辅助,先进先出
注意:
- 结点判重:判断是否已经访问过之前的节点
- 路径记录:一个结点可能扩展出多个结点,但最多只能有1个前驱(除了起始点),用到和节点数目等长的数组pre记录结点前驱pre[i]=j
深度优先搜索
DFS算法框架
深度优先搜索(Depth-First-Search)
可以用栈的方法实现
深度优先搜索可以解决很多问题,比如八皇后、数独、LCA问题(Tarjan算法)
1 | class Graph(object): |
最短路径
Dijkstra算法
是一种贪心算法,求出某点到所有点的最短路径,这样问题就解决。可以解决带权最短路径的问题,权值不能为负值。
优化:启发式A*算法、GIS
Floyd算法
又叫做插点法,用于寻找给定过的加权图中多源点之间最短路径算法。Floyd算法的权值是可以为负值的。
Bellman-ford算法
适用于单源节点到其他所有节点的最短路径。
最小生成树
Prim算法
以一个节点作为最小生成树的初始节点,然后以迭代的方式找出与最小生成树中各节点权重最小的边,加入到最小生成树汇总。如果加入后缠身回路,则跳过这条边,选择下一个节点。最终将所有节点都加入到生成树停止。小树–>大数
Kruskal算法
与Prim不同,Kruskal算法在找最小生成树结点前,对所有有权重边从小到大排序,将排序好的权重依次加入到最小生成树种,如果加入产生回路则跳过。最终将所有节点都加入到生成树停止。森林–>大树
为了加快判断候选边e的加入是否形成环,可以考虑用并查集的方法:把当前状态的每个连通子图保存在各自的集合中,候选边是否可以加入,转化成两个顶点是否位于同一集合中。
Kruskal算法可以解决MST问题。
拓扑排序
对一个有向无环图(Directed Acyclic Graph)G进行拓扑排序,将G中所有顶点排成线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在现行排序中出现在v之前。
相互关系不变形。拓扑排序是一种偏序的。