Python小白的数学建模课-图论的基本概念
% s* {! g0 ^: i. ~
: d4 s9 s: i% u5 H2 d( h- 图论中所说的图,不是图形图像或地图,而是指由顶点和边所构成的图形结构。
- 图论不仅与拓扑学、计算机数据结构和算法密切相关,而且正在成为机器学习的关键技术。
- 本系列结合数学建模的应用需求,来介绍 NetworkX 图论与复杂网络工具包的基本功能和典型算法。% D- u; k v/ D3 e, B+ a
( @4 \! K- P. z6 ^9 }) s! {2 _1. 图论1.1 图论是什么
; V. O# B; ]# E, F图论〔Graph Theory〕以图为研究对象,是离散数学的重要内容。图论不仅与拓扑学、计算机数据结构和算法密切相关,而且正在成为机器学习的关键技术。
7 M, f1 k# T4 i7 Y
K, h3 M) p* c( D& {' |) y) I1 h, ]图论中所说的图,不是指图形图像(image)或地图(map),而是指由顶点(vertex)和连接顶点的边(edge)所构成的关系结构。
, g6 A% E5 A) S
! H l* ^9 _, _9 J图提供了一种处理关系和交互等抽象概念的更好的方法,它还提供了直观的视觉方式来思考这些概念。
: O1 Y6 N) A6 @+ ?% d6 ~- Q6 n0 J# F0 i) {7 Z8 _, t6 Q
1.2 NetworkX 工具包0 }, x$ b! R+ T) ]: n8 G. o
NetworkX 是基于 Python 语言的图论与复杂网络工具包,用于创建、操作和研究复杂网络的结构、动力学和功能。1 @$ Q5 d0 [0 R& ~
+ M! E: J+ G6 v. t5 Z4 U
NetworkX 可以以标准和非标准的数据格式描述图与网络,生成图与网络,分析网络结构,构建网络模型,设计网络算法,绘制网络图形。4 g! a) w& i4 w+ r/ n" w
8 ^8 {7 l/ z% l$ g9 q% u8 e+ _+ ]1 Z
NetworkX 提供了图形的类、对象、图形生成器、网络生成器、绘图工具,内置了常用的图论和网络分析算法,可以进行图和网络的建模、分析和仿真。
1 \+ Y7 ? M; @, O' e
o6 K' T# N- l6 _! d; R+ z/ C# BNetworkX 的功能非常强大和庞杂,所涉及内容远远、远远地超出了数学建模的范围,甚至于很难进行系统的概括。本系列结合数学建模的应用需求,来介绍 NetworkX 图论与复杂网络工具包的基本功能和典型算法。7 e' g$ ]* T- A: Z
8 c( G$ E) F/ u% \$ S# g+ M& ~
' Y' x% Z; r6 \: c" q: }
2、图、顶点和边的创建与基本操作
+ x( r2 B* V! n8 ~. {' J/ O D0 ~图由顶点和连接顶点的边构成,但与顶点的位置、边的曲直长短无关。 Networkx 支持创建简单无向图、有向图和多重图;内置许多标准的图论算法,节点可为任意数据;支持任意的边值维度,功能丰富,简单易用。 2.1 图的基本概念7 z) L& {9 b0 [6 s0 ^- j, K
图(Graph):图是由若干顶点和连接顶点的边所构成关系结构。4 d5 l& i5 r( ~+ M
顶点(Node):图中的点称为顶点,也称节点。
7 r- b1 o# ~! q边(Edge):顶点之间的连线,称为边。
4 M% t# h3 L3 E8 d7 ^平行边(Parallel edge):起点相同、终点也相同的两条边称为平行边。9 c U, h7 |: _) v9 S8 W
循环(Cycle):起点和终点重合的边称为循环。- Y. b7 R/ j8 w5 @! F
有向图(Digraph):图中的每条边都带有方向,称为有向图。
) v! [" `; S t+ S2 @无向图(Undirected graph):图中的每条边都没有方向,称为无向图。2 r1 Z! V3 P# U; b; s6 I$ d* P. H
赋权图(Weighted graph):图中的每条边都有一个或多个对应的参数,称为赋权图。该参数称为这条边的权,权可以用来表示两点间的距离、时间、费用。, \# V# T, u0 F
度(Degree):与顶点相连的边的数量,称为该顶点的度。 L; G/ h8 ]6 W7 O5 r3 `: b+ e: u
8 p) ]" e* X0 s8 k2 b, p4 {: H
2.2 图、顶点和边的操作& q* H4 k/ p# G) h, w2 r
Networkx很容易创建图、向图中添加顶点和边、从图中删除顶点和边,也可以查看、删除顶点和边的属性。
, t# b% t. l* @7 O0 l) \, P
* v0 I0 @) C* I5 I: |: r2.2.1 图的创建Graph() 类、DiGraph() 类、MultiGraph() 类和 MultiDiGraph() 类分别用来创建:无向图、有向图、多图和有向多图。定义和例程如下:& R/ G9 N6 _3 N6 h, D- u; j
4 R" G8 z3 P& N9 z K' e0 Jclass Graph(incoming_graph_data=None, **attr)- `1 i; C3 X* f' D/ M
import networkx as nx # 导入 NetworkX 工具包
; e4 F( X7 Z I1 i& k( Q
7 ?0 |" N3 @$ |; N3 A% I1 o# 创建 图' M! V) P' V/ v( A5 F( M5 U+ S
G1 = nx.Graph() # 创建:空的 无向图/ a) K: F8 \1 p: [6 s( J
G2 = nx.DiGraph() #创建:空的 有向图+ e' c- A6 x& S0 k6 j5 O6 z! n
G3 = nx.MultiGraph() #创建:空的 多图
# L$ O" I2 c( hG4 = nx.MultiDiGraph() #创建:空的 有向多图
" [/ h2 o }* u. I- @" ]! `% m3 n, Q
1 C+ Z1 x7 Z# Q/ {1 ]2.2.2 顶点的添加、删除和查看
3 }! [; E# H7 j7 `! T4 I& M图的每个顶点都有唯一的标签属性(label),可以用整数或字符类型表示,顶点还可以自定义任意属性。 顶点的常用操作:添加顶点,删除顶点,定义顶点属性,查看顶点和顶点属性。定义和例程如下:
% [) D1 x6 g1 `8 V6 a! {Graph.add_node(node_for_adding, **attr)
0 Z) D7 a7 k( [+ FGraph.add_nodes_from(nodes_for_adding, **attr). k- B% e: C5 u, s. ]
Graph.remove_node(n) X X u1 t& W; h0 Z- A. |, h
Graph.remove_nodes_from(nodes)8 @" A- l9 i; ]* Q4 d) Z3 U/ P
5 e+ c2 x+ P1 X
# 顶点(node)的操作# G1 D5 f8 i2 e& O6 b0 v7 T% ^
# 向图中添加顶点
5 u2 b! O. b( X+ _5 }G1.add_node(1) # 向 G1 添加顶点 1
( Y) u5 ]2 ]8 x {8 N0 }G1.add_node(1, name='n1', weight=1.0) # 添加顶点 1,定义 name, weight 属性9 L: f+ H! P' ~4 b* ?5 y- d
G1.add_node(2, date='May-16') # 添加顶点 2,定义 time 属性
3 a1 @7 ?5 R, \4 a( m. K! G, ]G1.add_nodes_from([3, 0, 6], dist=1) # 添加多个顶点,并定义属性
* ^4 h+ R0 L: B" r% fG1.add_nodes_from(range(10, 15)) # 向图 G1 添加顶点 10~146 P9 W9 H$ l6 @+ g8 r( n1 s' r7 @
% g7 U L; E- m7 e! o
# 查看顶点和顶点属性+ g! _3 T; j/ C( f
print(G1.nodes()) # 查看顶点列表+ p, P1 M" a5 S) `7 w
# [1, 2, 3, 0, 6, 10, 11, 12, 13, 14]
& B* c: l4 A0 S9 @0 Zprint(G1._node) # 查看顶点属性/ D/ ]7 V0 R9 m7 r5 a
# {1: {'name': 'n1', 'weight': 1.0}, 2: {'date': 'May-16'}, 3: {'dist': 1}, 0: {'dist': 1}, 6: {'dist': 1}, 10: {}, 11: {}, 12: {}, 13: {}, 14: {}}
- f" b. c7 X7 W2 [' o1 I3 _, t/ u9 F1 C# \- w. T; m) H
# 从图中删除顶点
+ j3 C q* R k1 SG1.remove_node(1) # 删除顶点) _5 W9 A% Q V6 u- b4 r+ i; m: {
G1.remove_nodes_from([1, 11, 13, 14]) # 通过顶点标签的 list 删除多个顶点
W: Z6 o2 V6 P9 d& D7 }; aprint(G1.nodes()) # 查看顶点) S8 B. F5 m* t7 b8 H% @
# [2, 3, 0, 6, 10, 12] # 顶点列表
. I' E( Y O7 U' \0 D! |, g2.2.3 边的添加、删除和查看边是两个顶点之间的连接,在 NetworkX 中 边是由对应顶点的名字的元组组成 e=(node1,node2)。边可以设置权重、关系等属性。 边的常用操作:添加边,删除边,定义边的属性,查看边和边的属性。向图中添加边时,如果边的顶点是图中不存在的,则自动向图中添加该顶点。 Graph.add_edge(u_of_edge, v_of_edge, **attr)
( A: D# ?" v5 kGraph.add_edges_from(ebunch_to_add, **attr)+ F9 l" }( A! f f
Graph.add_weighted_edges_from(ebunch_to_add, weight=‘weight’, **attr)5 C/ p3 D, W0 D! h
: _$ j% ]3 s5 z" `3 \; r1 e) b
# 边(edge)的操作
( D; s1 Q# g& v+ B; L- m# a# 向图中添加边
- h& B: X! I, C$ J* P# w, J1 c" _G1.add_edge(1,5) # 向 G1 添加边,并自动添加图中没有的顶点
1 p4 f# a a7 i7 M* ~7 F/ a. o5 Q7 PG1.add_edge(0,10, weight=2.7) # 向 G1 添加边,并设置边的属性
, Q( i/ z( A; y6 M4 x& CG1.add_edges_from([(1,2,{'weight':0}), (2,3,{'color':'blue'})]) # 向图中添加边,并设置属性3 f. ^- h4 q7 a% h ~4 b, F& _# @
G1.add_edges_from([(3,6),(1,2),(6,7),(5,10),(0,1)]) # 向图中添加多条边
- G3 y7 G5 M, eG1.add_weighted_edges_from([(1,2,3.6),[6,12,0.5]]) # 向图中添加多条赋权边: (node1,node2,weight)- \8 u; R5 t2 {8 ?! q
print(G1.nodes()) # 查看顶点. X5 r5 {* d+ @( B5 h H' N1 v4 S
# [2, 3, 0, 6, 10, 12, 1, 5, 7] # 自动添加了图中没有的顶点
, |' _9 s( q5 V' `; T' E$ A/ e$ D/ z9 X
# 从图中删除边; _; X* \! C; @: ?) n& M+ b
G1.remove_edge(0,1) # 从图中删除边 0-18 }; L/ p7 Q: K$ i! ~3 H7 |( ]
G1.remove_edges_from([(2,3),(1,5),(6,7)]) # 从图中删除多条边
4 T @5 k* ?& `
6 _! t+ Z b' h/ a( q# 查看 边和边的属性# j7 w' b! f" y2 [; K+ ?
print(G1.edges) # 查看所有的边7 u7 k4 a2 ]+ D: k
[(2, 1), (3, 6), (0, 10), (6, 12), (10, 5)]5 d. x4 l" I" U* W0 |5 u; k
print(G1.get_edge_data(1,2)) # 查看指定边的属性
9 L. ~" y* F7 e8 t4 ~9 F; n# {'weight': 3.6}" [) r+ x2 X. ~/ a+ n- e
print(G1[1][2]) # 查看指定边的属性" t* T. A, X" \" F$ j, d
# {'weight': 3.6}6 @, e( Y; d6 k
print(G1.edges(data=True)) # 查看所有边的属性
x T* M/ ~1 Q( s& K, K# [(2, 1, {'weight': 3.6}), (3, 6, {}), (0, 10, {'weight': 2.7}), (6, 12, {'weight': 0.5}), (10, 5, {})]
9 c5 i, t. e9 Z/ \# ^ G) F, H3 O1 ?6 G! k1 C- L
2.2.4 查看图、顶点和边的信息& N9 q' c+ V1 q6 i9 S# ?
) N# Q* d5 g- `4 ]& W, B! q
# 查看图、顶点和边的信息
$ Y( t* n% I5 @% `' @/ Kprint(G1.nodes) # 返回所有的顶点 [node1,...]2 P% ^# a* m5 X1 L+ @" `
# [2, 3, 0, 6, 10, 12, 1, 5, 7]+ x+ j$ a/ ~( Y& s/ w2 E
print(G1.edges) # 返回所有的边 [(node1,node2),...]
8 |: y0 u) K% G# [(2, 1), (3, 6), (0, 10), (6, 12), (10, 5)]
: b8 n' P, A2 U3 p& t8 [5 wprint(G1.degree) # 返回各顶点的度 [(node1,degree1),...]4 R6 x1 Z" J6 v$ a2 W
# [(2, 1), (3, 1), (0, 1), (6, 2), (10, 2), (12, 1), (1, 1), (5, 1), (7, 0)]/ [$ S3 P+ Z- O! t+ [
print(G1.number_of_nodes()) # 返回顶点的数量+ @. D; X9 I- m, C
# 98 {4 }* _+ D: _) T3 l6 K
print(G1.number_of_edges()) # 返回边的数量/ E/ n5 \) J- ^/ }4 M
# 5) j! c0 O% k2 F6 k1 s2 ?
print(G1[10]) # 返回与指定顶点相邻的所有顶点的属性
' A, J4 G& N8 \! P# {0: {'weight': 2.7}, 5: {}}! h1 `, e0 V! A+ Y+ N& ~/ K3 k, c
print(G1.adj[10]) # 返回与指定顶点相邻的所有顶点的属性
& u- m; m# H8 J, C& g# {0: {'weight': 2.7}, 5: {}}3 U: |5 n0 z$ H3 T
print(G1[1][2]) # 返回指定边的属性, y* A2 A$ s& M/ p" W+ r
# {'weight': 3.6}
6 ]6 k. ^6 r) A! @" c ^print(G1.adj[1][2]) # 返回指定边的属性
7 ~: f! U3 L' ?. q( z0 \1 G/ N3 c# {'weight': 3.6}
$ z7 V" M3 W2 Kprint(G1.degree(10)) # 返回指定顶点的度: K( w% _* q% ~7 l {0 v# F, V
# 2' i7 t* j. @; }9 Z* n
8 r2 o- S) ?) \( B1 Q' u; m3 g
print('nx.info:',nx.info(G1)) # 返回图的基本信息
1 Y8 P3 f7 Y( s) x7 j7 O4 }# Lprint('nx.degree:',nx.degree(G1)) # 返回图中各顶点的度+ d6 v8 Y% Q$ V O ^7 e
print('nx.density:',nx.degree_histogram(G1)) # 返回图中度的分布( g0 ]2 S4 |3 }& v* Q
print('nx.pagerank:',nx.pagerank(G1)) # 返回图中各顶点的频率分布
- c; c# w7 Q9 w& L! w8 e
7 U4 _1 {) x; k9 J7 d: [$ L- I! r: Z) u; K0 U
( p$ U) O. i3 m$ \
3 |) L8 \; Z* v# Q, [9 E5 Z
7 O1 L$ N% I K& ?! c1 Q
2.3 图的属性和方法图的方法
6 m! @8 }. R5 Q& }% R4 a' M
, F+ l: _9 A3 r; \$ o9 e5 b7 }方法 说明; J, u! s( O) E( ^- ]" {- `
G.has_node(n) 当图 G 中包括顶点 n 时返回 True/ B2 Z: J7 M$ l% O0 }" n
G.has_edge(u, v) 当图 G 中包括边 (u,v) 时返回 True
7 N. o+ p2 Q' X3 QG.number_of_nodes() 返回 图 G 中的顶点的数量
3 U' B, R. o6 xG.number_of_edges() 返回 图 G 中的边的数量
' }) Y* m; C: j0 U6 g; U! FG.number_of_selfloops() 返回 图 G 中的自循环边的数量
1 b# y% m5 d4 e4 U7 f/ u! [9 hG.degree([nbunch, weight]) 返回 图 G 中的全部顶点或指定顶点的度9 g# x5 t' W6 B5 `$ {
G.selfloop_edges([data, default]) 返回 图 G 中的全部的自循环边
. f5 U, V2 ^9 e& @( X( P9 d, JG.subgraph([nodes]) 从图 G1中抽取顶点[nodes]及对应边构成的子图
/ _# v5 w" L* O6 w' Z& \- [union(G1,G2) 合并图 G1、G2
, t0 ~' @8 w- t2 O3 rnx.info(G) 返回图的基本信息( T9 X5 [% Y, X; R- A- {
nx.degree(G) 返回图中各顶点的度- D! w5 l, O! q. ^, m
nx.degree_histogram(G) 返回图中度的分布( h- N' l) i: \8 v0 E, V' e* S( {
nx.pagerank(G) 返回图中各顶点的频率分布
/ P9 k0 U1 \3 u! \' cnx.add_star(G,[nodes],**attr) 向图 G 添加星形网络
M9 b. _9 A t! H2 B% qnx.add_path(G,[nodes],**attr) 向图 G 添加一条路径6 H: F5 o9 [% ]3 X1 R
nx.add_cycle(G,[nodes],**attr) 向图 G 添加闭合路径$ T5 I, o" P" P, f5 ?* L! m& F$ h
: j% s& W8 X0 b, H( J
. i' ]+ _0 m: b例程:" x" u6 C! ~3 D% ?- d
G1.clear() # 清空图G1/ E. { ^7 i& P
nx.add_star(G1, [1, 2, 3, 4, 5], weight=1) # 添加星形网络:以第一个顶点为中心. U6 ]! U5 Z3 u2 E1 F. ~
# [(1, 2), (1, 3), (1, 4), (1, 5)]
$ }2 w+ @9 J7 Q! R4 n+ Inx.add_path(G1, [5, 6, 8, 9, 10], weight=2) # 添加路径:顺序连接 n个节点的 n-1条边
9 \6 D2 }( f9 C$ p# [(5, 6), (6, 8), (8, 9), (9, 10)], U" \$ B' P# h3 L9 Z* x
nx.add_cycle(G1, [7, 8, 9, 10, 12], weight=3) # 添加闭合回路:循环连接 n个节点的 n 条边4 ~* R) L \# q' m- c1 N
# [(7, 8), (7, 12), (8, 9), (9, 10), (10, 12)]
) N! ?1 M0 c' t/ Xprint(G1.nodes) # 返回所有的顶点 [node1,...]
M" p. }% j4 fnx.draw_networkx(G1)8 b* F9 \1 m. c- q) j& K5 [. n% c
plt.show()
, u( V C% d! z4 X8 N0 k& T/ J% L0 B( b0 B2 y7 [: j+ N
G2 = G1.subgraph([1, 2, 3, 8, 9, 10])
K8 a" ~8 c2 Z tG3 = G1.subgraph([4, 5, 6, 7])4 E7 M- c; J" ~. y s
G = nx.union(G2, G3)
/ e- }8 g: y. m+ n* bprint(G.nodes) # 返回所有的顶点 [node1,...]3 w7 Y3 t" E4 n" |0 j; R
# [1, 2, 3, 8, 9, 10, 4, 5, 6, 7]
9 Z3 t' c1 {7 k3 {4 y
& m0 ~! @" w* i0 V3 N8 p. W
) |# M0 G3 [# c+ T3、图的绘制与分析3.1 图的绘制+ E6 Z" s. N6 x: x0 M8 x- f
可视化是图论和网络问题中很重要的内容。NetworkX 在 Matplotlib、Graphviz 等图形工具包的基础上,提供了丰富的绘图功能。
8 r, M% n V; g+ u5 d% N' c2 `0 s. [ E, n2 O5 U- ^# c1 O0 O- }$ m
本系列拟对图和网络的可视化作一个专题,在此只简单介绍基于 Matplotlib 的基本绘图函数。基本绘图函数使用字典提供的位置将节点放置在散点图上,或者使用布局函数计算位置。
9 Q a) ^; c) s! m! L% s8 C
) T" M6 W* U6 P/ v方法 说明- K; x2 Z/ l) r7 s
draw(G[,pos,ax]) 基于 Matplotlib 绘制 图 G
' H) x) k: b, p6 H# H: f6 I% j. d- ]draw_networkx(G[, pos, arrows, with_labels]) 基于 Matplotlib 绘制 图 G% `- G- L0 F: S& r/ W& b9 z }
draw_networkx_nodes(G, pos[, nodelist, . . . ]) 绘制图 G 的顶点) N3 b1 Y& l/ z0 i' K
draw_networkx_edges(G, pos[, edgelist, . . . ]) 绘制图 G 的边0 ]6 d: j/ N' Z# V7 x
draw_networkx_labels(G, pos[, labels, . . . ]) 绘制顶点的标签
7 x$ M, m3 `" A l# edraw_networkx_edge_labels(G, pos[, . . . ]) 绘制边的标签
' c! }& G4 e$ u2 f4 R
8 B% ^4 M" u- F/ o
1 k7 K* z6 d( F5 L; W其中,nx.draw() 和 nx.draw_networkx() 是最基本的绘图函数,并可以通过自定义函数属性或其它绘图函数设置不同的绘图要求。) w* q7 O3 b( U3 B+ N
draw(G, pos=None, ax=None, **kwds) draw_networkx(G, pos=None, arrows=True, with_labels=True, **kwds) # q2 W- Q2 o3 ?+ O6 J( K! M
常用的属性定义如下:* Y! Z q( F( N2 g
+ ~0 i6 Q _/ G; {7 a8 b8 d
‘node_size’:指定节点的尺寸大小,默认300
- m: g% E* z" f8 ^7 [, D, w* I‘node_color’:指定节点的颜色,默认红色3 ?2 f q/ H$ Q( |
‘node_shape’:节点的形状,默认圆形9 ^! ]4 Z$ P9 U$ K4 Z/ Z
'‘alpha’:透明度,默认1.0,不透明' r) x) Z0 U+ V }! M1 N
‘width’:边的宽度,默认1.0
1 @9 k& I* N0 Y a m. Q4 B‘edge_color’:边的颜色,默认黑色) _$ B) b' t( L/ s6 |1 }
‘style’:边的样式,可选 ‘solid’、‘dashed’、‘dotted’、‘dashdot’
' ?0 G m, f- p, T5 O9 O/ u7 B‘with_labels’:节点是否带标签,默认True3 j. P8 _* u2 ~, p8 y
‘font_size’:节点标签字体大小,默认12
# V4 Q- H. S y% ?3 |‘font_color’:节点标签字体颜色,默认黑色
' K/ v6 \6 t9 h( M& u0 Q" Q3 Y# S* }. j8 F
% u2 ?+ L* V- }
3.2 图的分析NetwotkX 提供了图论函数对图的结构进行分析4 D% C0 O/ G9 }0 ~( q1 ^
子图# } K; P4 h. b$ g6 L; g5 l
- 子图是指顶点和边都分别是图 G 的顶点的子集和边的子集的图。
- subgraph()方法,按顶点从图 G 中抽出子图。例程如前。
1 R/ k9 g- ^+ B" c 连通子图- q" e8 T) P6 A! {0 b9 T
1 b" x& p' A0 D0 p- 如果图 G 中的任意两点间相互连通,则 G 是连通图。
- [color=rgba(0, 0, 0, 0.749019607843137)]connected_components()方法,返回连通子图的集合。% g7 ^, v. r4 x7 {* G; v
[color=rgba(0, 0, 0, 0.749019607843137)]G = nx.path_graph(4)[color=rgba(0, 0, 0, 0.749019607843137)]nx.add_path(G, [7, 8, 9])[color=rgba(0, 0, 0, 0.749019607843137)]# 连通子图[color=rgba(0, 0, 0, 0.749019607843137)]listCC = [len(c) for c in sorted(nx.connected_components(G), key=len, reverse=True)][color=rgba(0, 0, 0, 0.749019607843137)]maxCC = max(nx.connected_components(G), key=len)[color=rgba(0, 0, 0, 0.749019607843137)]print('Connected components:{}'.format(listCC)) # 所有连通子图[color=rgba(0, 0, 0, 0.749019607843137)]# Connected components:[4, 3][color=rgba(0, 0, 0, 0.749019607843137)]print('Largest connected components:{}'.format(maxCC)) # 最大连通子图[color=rgba(0, 0, 0, 0.749019607843137)]# Largest connected components:{0, 1, 2, 3}[color=rgba(0, 0, 0, 0.749019607843137)]强连通如果有向图 G 中的任意两点间相互连通,则称 G 是强连通图。strongly_connected_components()方法,返回所有强连通子图的列表。# 强连通G = nx.path_graph(4, create_using=nx.DiGraph())nx.add_path(G, [3, 8, 1])# 找出所有的强连通子图con = nx.strongly_connected_components(G)print(type(con),list(con))# <class 'generator'> [{8, 1, 2, 3}, {0}]弱连通如果一个有向图 G 的基图是连通图,则有向图 G 是弱连通图。weakly_connected_components()方法,返回所有弱连通子图的列表。# 弱连通G = nx.path_graph(4, create_using=nx.DiGraph()) #默认生成节点 0,1,2,3 和有向边 0->1,1->2,2->3nx.add_path(G, [7, 8, 3]) #生成有向边:7->8->3con = nx.weakly_connected_components(G)print(type(con),list(con))# <class 'generator'> [{0, 1, 2, 3, 7, 8}]+ Q) {6 o, ^- m- E
$ y$ {/ [8 K/ `3 Q( v! F0 E
$ Q! y; N4 q) s* g( f/ M" ?; `$ y7 U3 U
: O: t4 i, B/ m7 M: c w& t. m |