-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathGraphClass.py
283 lines (250 loc) · 9.4 KB
/
GraphClass.py
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
"""
图(Graph):表示多对多的关系,包括:
1.一组顶点:通常V(Vertex)表示顶点集合
2.一组边:通常用E(Edge)表示边的集合
1.边是定点对:(v, w)属于E,其中v和w属于V
2.有向边<v, w>表示v指向w的边
3.不考虑重边和自回路
数据对象集:G(V,E)由非空的有限顶点集合V和一个有限边集合E组成
操作集:creat():建立图
insertVertex(v) 插入v
insertEdge(e) 插入e
DFS(v) 从v开始深度优先遍历
BFS(v) 从v开始广度优先遍历
shortestPath(v) 计算v到其它顶点的最短路径
MST() 计算最小生成树
常见术语:无向图;有向图;网络(带权图)...
连通:如果v到w存在一条(无向)路径,则称v和w是连通的
路径:v到w的路径是一系列顶点{v,...,w}的集合,相邻顶点间有图中的边
路径长度:路径边数(如果带权,则为权重和)
简单路径:路径中所有顶点都不同
回路:起点等于终点的路径
连通图:图中任意两顶点均连通
连通分量: 无向图的极大连通图(极大顶点数,极大边数)
强连通:有向图v和w之间存在双向路径
强连通图:任意两顶点均强连通
强连通分量:有向图的极大强连通子图
"""
"""
邻接矩阵表示图
优点:1. 直观,简单,好理解
2. 方便检查任意一对顶点间是否存在边
3. 方便找任意顶点的所有邻接点
4. 方便计算顶点的度
缺点:稀疏图浪费空间和时间
"""
"""
邻接表表示图:
优点:1. 方便找任一顶点的所有临接点
2. 适合表示稀疏图
3. 方便计算无向图的度,和有向图的出度;需要构造“逆邻接表”计算入度
缺点:不方便检查任意一对顶点间是否存在边
"""
"""
遍历:深度优先搜索(类似于树的先序遍历),广度优先搜索(类似于树的层次遍历)
"""
from collections import deque
# 有向图的邻接矩阵表示
class MatrixGraph:
def __init__(self, vertex_num=0, edge=None):
"""
用>=0的整数表示各个顶点,可以使用vertex_num*vertex_num的列表表示图
:param vertex_num 顶点数目
:param edge 形如[[v1, v2],...]表示v1到v2的边
"""
self._vertex_num = 0
self._graph = []
self._search_num = 1
self._if_search = []
self.insert_vertex(vertex_num)
if edge is not None:
self.insert_edge(edge)
@property
def vertex_num(self):
return self._vertex_num
@property
def graph(self):
return self._graph
def insert_vertex(self, n=1):
"""
:param n: 插入顶点数量
"""
self._vertex_num += n
for vertex in self._graph:
vertex.extend([0] * n)
for i in range(n):
self._graph.append([0]*self._vertex_num)
self._if_search.append(self._search_num)
def insert_edge(self, edges):
"""
:param edges: 插入边
"""
for start_vertex, end_vertex in edges:
self._graph[start_vertex][end_vertex] = 1
def DFT(self):
"""
深度优先遍历
"""
self._search_num = -self._search_num
for i in range(self._vertex_num):
if self._if_search[i] != self._search_num:
self._DFT_each_vertex(i)
def _DFT_each_vertex(self, vertex_index):
"""
:param vertex_index: 以vertex_index为起点,递归遍历图
"""
print(vertex_index)
self._if_search[vertex_index] = self._search_num
for i in range(self._vertex_num):
if self._graph[vertex_index][i] == 1 and self._if_search[i] != self._search_num:
self._DFT_each_vertex(i)
def BFT(self):
"""
广度优先遍历
"""
self._search_num = -self._search_num
for i in range(self._vertex_num):
if self._if_search[i] != self._search_num:
self._BFT_each_vertex(i)
def _BFT_each_vertex(self, vertex_index):
"""
:param vertex_index: 以vertex_index为起点,循环遍历图
"""
vertex_level = deque()
vertex_level.append(vertex_index)
self._if_search[vertex_index] = self._search_num
while vertex_level:
vertex_index_get = vertex_level.popleft()
print(vertex_index_get)
for i in range(self._vertex_num):
if self._graph[vertex_index_get][i] == 1 and self._if_search[i] != self._search_num:
vertex_level.append(i)
self._if_search[i] = self._search_num
def shortest_path(self, vertex_index):
"""
:param vertex_index:
:return: 获得vertex_index该顶点到其他顶点的最短路径及其长度
"""
vertex_length = dict()
path = dict()
for i in range(self._vertex_num):
vertex_length[i] = -1
vertex_deque = deque()
vertex_deque.append(vertex_index)
vertex_length[vertex_index] = 0
while vertex_deque:
index_1 = vertex_deque.popleft()
for index_2 in range(self._vertex_num):
if self._graph[index_1][index_2] == 1 and vertex_length[index_2] == -1:
vertex_length[index_2] = vertex_length[index_1] + 1
path[index_2] = index_1
vertex_deque.append(index_2)
return vertex_length, path
# 有向图的邻接表表示
class ListGraph:
def __init__(self, vertex_num=0, edge=None):
"""
用>=0的整数表示各个顶点,可以使用vertex_num的列表表示图,列表中的元素为链表,表示该顶点指向的顶点,为了方便,使用列表代替链表
:param vertex_num 顶点数目
:param edge 形如[[v1, v2],...]表示v1到v2的边
"""
self._vertex_num = 0
self._graph = []
self._search_num = 1
self._if_search = []
self.insert_vertex(vertex_num)
if edge is not None:
self.insert_edge(edge)
@property
def vertex_num(self):
return self._vertex_num
@property
def graph(self):
return self._graph
def insert_vertex(self, n=1):
"""
:param n: 插入顶点数量
"""
self._vertex_num += n
for i in range(n):
self._graph.append([])
self._if_search.append(self._search_num)
def insert_edge(self, edges):
"""
:param edges: 插入边
"""
for start_vertex, end_vertex in edges:
if end_vertex not in self._graph[start_vertex]:
self._graph[start_vertex].append(end_vertex)
def DFT(self):
"""
深度优先遍历
"""
self._search_num = -self._search_num
for i in range(self._vertex_num):
if self._if_search[i] != self._search_num:
self._DFT_each_vertex(i)
def _DFT_each_vertex(self, vertex_index):
"""
:param vertex_index: 以vertex_index为起点,递归遍历图
"""
print(vertex_index)
self._if_search[vertex_index] = self._search_num
for i in self._graph[vertex_index]:
if self._if_search[i] != self._search_num:
self._DFT_each_vertex(i)
def BFT(self):
"""
广度优先遍历
"""
self._search_num = -self._search_num
for i in range(self._vertex_num):
if self._if_search[i] != self._search_num:
self._BFT_each_vertex(i)
def _BFT_each_vertex(self, vertex_index):
"""
:param vertex_index: 以vertex_index为起点,循环遍历图
"""
vertex_level = deque()
vertex_level.append(vertex_index)
self._if_search[vertex_index] = self._search_num
while vertex_level:
vertex_index_get = vertex_level.popleft()
print(vertex_index_get)
for i in self._graph[vertex_index_get]:
if self._if_search[i] != self._search_num:
vertex_level.append(i)
self._if_search[i] = self._search_num
def shortest_path(self, vertex_index):
"""
:param vertex_index:
:return: 获得vertex_index该顶点到其他顶点的最短路径及其长度
"""
vertex_length = dict()
path = dict()
for i in range(self._vertex_num):
vertex_length[i] = -1
vertex_deque = deque()
vertex_deque.append(vertex_index)
vertex_length[vertex_index] = 0
while vertex_deque:
index_1 = vertex_deque.popleft()
for index_2 in self._graph[index_1]:
if vertex_length[index_2] == -1:
vertex_length[index_2] = vertex_length[index_1] + 1
path[index_2] = index_1
vertex_deque.append(index_2)
return vertex_length, path
def test():
# graph = ListGraph(5, [[0, 1], [0, 2], [1, 2], [1, 3], [2, 3], [2, 4], [3, 1], [4, 1], [4, 2], [4, 3]])
graph = MatrixGraph(5, [[0, 1], [0, 2], [1, 2], [1, 3], [2, 3], [2, 4], [3, 1], [4, 1], [4, 2], [4, 3]])
graph.insert_vertex()
graph.insert_edge([[5, 1], [5, 2], [1, 5]])
# graph.DFT()
print("===")
# graph.BFT()
length, path = graph.shortest_path(1)
print(length)
print(path)
if __name__ == "__main__":
test()