Python小白的数学建模课-图论的基本概念8 \/ s% @! R# k' i K8 D0 p3 U/ w0 k
2 z; x( p% Q& N( X( Y- 图论中所说的图,不是图形图像或地图,而是指由顶点和边所构成的图形结构。
- 图论不仅与拓扑学、计算机数据结构和算法密切相关,而且正在成为机器学习的关键技术。
- 本系列结合数学建模的应用需求,来介绍 NetworkX 图论与复杂网络工具包的基本功能和典型算法。3 x; S+ Q4 S, G; ~; |& ]
6 i' z8 x4 y) r8 v
1. 图论1.1 图论是什么9 K- K: g7 G/ E- _ S
图论〔Graph Theory〕以图为研究对象,是离散数学的重要内容。图论不仅与拓扑学、计算机数据结构和算法密切相关,而且正在成为机器学习的关键技术。
4 s: m0 @: D1 d7 O4 H; W+ x7 c) c7 Z* C e2 j' N: B$ m$ ]# q1 k
图论中所说的图,不是指图形图像(image)或地图(map),而是指由顶点(vertex)和连接顶点的边(edge)所构成的关系结构。$ E% Y+ |1 A" a% U6 f- d
' _' f$ v; d7 L- ^, c" B8 U
图提供了一种处理关系和交互等抽象概念的更好的方法,它还提供了直观的视觉方式来思考这些概念。
9 Q" z/ D: z, u/ D1 F
6 v$ q( F0 K- l- _1.2 NetworkX 工具包6 ]7 G% o0 B- H
NetworkX 是基于 Python 语言的图论与复杂网络工具包,用于创建、操作和研究复杂网络的结构、动力学和功能。
9 e. L0 o1 h4 [" c* S* g' ^; l0 o
NetworkX 可以以标准和非标准的数据格式描述图与网络,生成图与网络,分析网络结构,构建网络模型,设计网络算法,绘制网络图形。* D/ v6 {! j R j( W
* ^! g) p a- h4 ?& g1 F1 i8 X& YNetworkX 提供了图形的类、对象、图形生成器、网络生成器、绘图工具,内置了常用的图论和网络分析算法,可以进行图和网络的建模、分析和仿真。
+ q N8 R5 w7 ?: J
& w8 e& U8 i1 L& h( O) ?- L0 y0 ^NetworkX 的功能非常强大和庞杂,所涉及内容远远、远远地超出了数学建模的范围,甚至于很难进行系统的概括。本系列结合数学建模的应用需求,来介绍 NetworkX 图论与复杂网络工具包的基本功能和典型算法。( K: f! X8 z+ B7 A
# r. q9 _+ Z+ Y% X, e( v![]()
' k( [# p0 w5 X; ^2、图、顶点和边的创建与基本操作% B6 m( j% S1 W5 ^
图由顶点和连接顶点的边构成,但与顶点的位置、边的曲直长短无关。 Networkx 支持创建简单无向图、有向图和多重图;内置许多标准的图论算法,节点可为任意数据;支持任意的边值维度,功能丰富,简单易用。 2.1 图的基本概念' P! p+ O/ v6 }; U4 g
图(Graph):图是由若干顶点和连接顶点的边所构成关系结构。% `7 F* O0 ]+ m: V
顶点(Node):图中的点称为顶点,也称节点。( H8 J4 z5 b7 g* ], C7 z
边(Edge):顶点之间的连线,称为边。0 [1 y. x7 _( y8 f) ~! K- j( {
平行边(Parallel edge):起点相同、终点也相同的两条边称为平行边。6 Z; Y! Q" g/ C, [1 u
循环(Cycle):起点和终点重合的边称为循环。) G/ z" c- r8 b- ^, ?# p
有向图(Digraph):图中的每条边都带有方向,称为有向图。
2 h6 G" t* \' @无向图(Undirected graph):图中的每条边都没有方向,称为无向图。
8 p6 a2 @2 N2 g赋权图(Weighted graph):图中的每条边都有一个或多个对应的参数,称为赋权图。该参数称为这条边的权,权可以用来表示两点间的距离、时间、费用。1 k/ h$ g/ c+ |- U
度(Degree):与顶点相连的边的数量,称为该顶点的度。6 G. V/ M+ r/ V; W( Y4 ]& {
: @, K: e1 ]0 l4 x" I2.2 图、顶点和边的操作
1 G; R6 |! D, y3 T3 aNetworkx很容易创建图、向图中添加顶点和边、从图中删除顶点和边,也可以查看、删除顶点和边的属性。
1 N8 r$ u$ T; x1 V0 E7 d
3 Q1 G! y' P5 k# }2.2.1 图的创建Graph() 类、DiGraph() 类、MultiGraph() 类和 MultiDiGraph() 类分别用来创建:无向图、有向图、多图和有向多图。定义和例程如下:6 \0 m9 Z) A! }+ j9 Y
3 q- u- D2 T% Q# eclass Graph(incoming_graph_data=None, **attr)
! `" [ ?6 \ F6 ~1 m% @import networkx as nx # 导入 NetworkX 工具包8 l2 m* X& _! G# b& X! P2 _/ {- t4 a0 V
: @; ]2 |- E) l# 创建 图 y$ d0 w. S6 Z
G1 = nx.Graph() # 创建:空的 无向图
, i+ _& H0 g* J/ X# F0 pG2 = nx.DiGraph() #创建:空的 有向图, T2 J7 i2 G: s2 M3 h; C
G3 = nx.MultiGraph() #创建:空的 多图$ r" H; S6 L5 Y7 O1 ]( h
G4 = nx.MultiDiGraph() #创建:空的 有向多图$ p7 x& S, o! h. z2 n0 y/ r
~. q6 r9 G: S3 h: J$ e
5 C/ p* t/ ?' u' G2.2.2 顶点的添加、删除和查看9 R7 ^) d! |& o L
图的每个顶点都有唯一的标签属性(label),可以用整数或字符类型表示,顶点还可以自定义任意属性。 顶点的常用操作:添加顶点,删除顶点,定义顶点属性,查看顶点和顶点属性。定义和例程如下: 5 t: n R' I7 Z R
Graph.add_node(node_for_adding, **attr)
! ~! q8 U5 o! ?2 \, o) QGraph.add_nodes_from(nodes_for_adding, **attr)7 _8 t6 ?9 d* z: m" I
Graph.remove_node(n)3 { j2 j4 ?( O8 ? S
Graph.remove_nodes_from(nodes)+ C& Z- R' }; ~/ h/ ^. \+ ]3 J2 T
% k& w8 L8 g7 ]# 顶点(node)的操作) t2 a, L+ W; w" _( f8 Z
# 向图中添加顶点3 e" e0 D h& f. `* Q s
G1.add_node(1) # 向 G1 添加顶点 1/ F% K2 o( Q) B3 B' G3 |6 l: W9 P
G1.add_node(1, name='n1', weight=1.0) # 添加顶点 1,定义 name, weight 属性
# P. `5 U2 c6 g+ AG1.add_node(2, date='May-16') # 添加顶点 2,定义 time 属性
" e8 ~6 f/ H, t% U2 ZG1.add_nodes_from([3, 0, 6], dist=1) # 添加多个顶点,并定义属性% g0 s) ~6 G- e6 S: R, D
G1.add_nodes_from(range(10, 15)) # 向图 G1 添加顶点 10~14
# \0 X: r! ]# t+ a- L8 W8 J0 y6 E: T' X M
# 查看顶点和顶点属性
& f) m! q+ V& b. k* _5 z6 Y8 iprint(G1.nodes()) # 查看顶点列表) Q; D0 z+ v" ^1 a
# [1, 2, 3, 0, 6, 10, 11, 12, 13, 14]
8 m; B4 V5 J5 b# f0 O5 Oprint(G1._node) # 查看顶点属性& r: U! v8 `1 O$ M; p2 J4 _$ q. Y
# {1: {'name': 'n1', 'weight': 1.0}, 2: {'date': 'May-16'}, 3: {'dist': 1}, 0: {'dist': 1}, 6: {'dist': 1}, 10: {}, 11: {}, 12: {}, 13: {}, 14: {}}+ L' L! z5 S0 S9 M
/ s' I/ m* Y9 n& S4 S# 从图中删除顶点
% \" H3 l$ ]- w+ ~' o0 |" w( e: I- KG1.remove_node(1) # 删除顶点
; ]1 ?. l# p$ w7 u- eG1.remove_nodes_from([1, 11, 13, 14]) # 通过顶点标签的 list 删除多个顶点( R$ \: X6 Q3 t; i- g( S# f% B: _
print(G1.nodes()) # 查看顶点 H% g; R) v# U; p; Q$ c
# [2, 3, 0, 6, 10, 12] # 顶点列表- g' k+ U* g7 _: Z+ h
2.2.3 边的添加、删除和查看边是两个顶点之间的连接,在 NetworkX 中 边是由对应顶点的名字的元组组成 e=(node1,node2)。边可以设置权重、关系等属性。 边的常用操作:添加边,删除边,定义边的属性,查看边和边的属性。向图中添加边时,如果边的顶点是图中不存在的,则自动向图中添加该顶点。 Graph.add_edge(u_of_edge, v_of_edge, **attr)
- d0 H- V* l% J9 q3 O mGraph.add_edges_from(ebunch_to_add, **attr)
$ [# }! E0 Y# V+ M1 dGraph.add_weighted_edges_from(ebunch_to_add, weight=‘weight’, **attr) l, Y7 R0 ^# [: I7 v! ?
" ~ u T# r" X3 B" u. M. P
# 边(edge)的操作$ Z; Z. k2 Q6 m T& {& g
# 向图中添加边
2 E8 \* N) T" m S1 WG1.add_edge(1,5) # 向 G1 添加边,并自动添加图中没有的顶点
8 N5 l- E+ c. I2 M) b& cG1.add_edge(0,10, weight=2.7) # 向 G1 添加边,并设置边的属性
* [: K! q; A8 p5 MG1.add_edges_from([(1,2,{'weight':0}), (2,3,{'color':'blue'})]) # 向图中添加边,并设置属性" }" B; X' q+ [
G1.add_edges_from([(3,6),(1,2),(6,7),(5,10),(0,1)]) # 向图中添加多条边
- c1 E V2 v8 F) y$ X) m0 GG1.add_weighted_edges_from([(1,2,3.6),[6,12,0.5]]) # 向图中添加多条赋权边: (node1,node2,weight)( N' m0 s5 A- Q% Y8 n! W
print(G1.nodes()) # 查看顶点
/ g$ u/ I, f8 P9 e& H7 l# [2, 3, 0, 6, 10, 12, 1, 5, 7] # 自动添加了图中没有的顶点4 G8 n+ l: ^4 _/ R( n
3 l5 h5 f$ \' o1 ?" N- P
# 从图中删除边
3 w' `" p4 p) K/ FG1.remove_edge(0,1) # 从图中删除边 0-1( h. }( x, L+ c# L# [
G1.remove_edges_from([(2,3),(1,5),(6,7)]) # 从图中删除多条边
: q# u( \' i# l* b0 h; B
. T1 D) }9 p9 r+ N6 W8 l& x: y# 查看 边和边的属性
# U7 d9 ]7 e1 ~! r) w$ r, A$ gprint(G1.edges) # 查看所有的边
9 N# h; r* X1 n/ Q0 a; c/ M, b[(2, 1), (3, 6), (0, 10), (6, 12), (10, 5)]
" S5 j4 A4 Z0 E* xprint(G1.get_edge_data(1,2)) # 查看指定边的属性
# l1 N) I' Z: Y# U# {'weight': 3.6}
) B! O4 _) e9 g ]3 tprint(G1[1][2]) # 查看指定边的属性) ~2 \- k& U: j$ G
# {'weight': 3.6}- `$ [/ s) y8 d* v' F+ k9 P2 ~+ z: Q
print(G1.edges(data=True)) # 查看所有边的属性
, u& B8 W' K% d3 b/ O# [(2, 1, {'weight': 3.6}), (3, 6, {}), (0, 10, {'weight': 2.7}), (6, 12, {'weight': 0.5}), (10, 5, {})]
0 }+ c) N h. c4 p2 U; _" O
4 R( I K& u) T. W2.2.4 查看图、顶点和边的信息5 _3 _$ y" j3 L& Z2 E! \) w
- w/ q+ W9 }& f, {6 v4 W# 查看图、顶点和边的信息
' _, P4 ?1 Z# q) B9 O8 dprint(G1.nodes) # 返回所有的顶点 [node1,...]8 d$ @/ h3 Y' q
# [2, 3, 0, 6, 10, 12, 1, 5, 7]
0 ]0 P1 ]- N/ t9 E9 Jprint(G1.edges) # 返回所有的边 [(node1,node2),...]
, X1 f" d9 p; Z) F- D4 _- [# M# [(2, 1), (3, 6), (0, 10), (6, 12), (10, 5)]
2 U5 [0 v: I& S8 E. u9 \print(G1.degree) # 返回各顶点的度 [(node1,degree1),...]7 p: V( {9 h* H
# [(2, 1), (3, 1), (0, 1), (6, 2), (10, 2), (12, 1), (1, 1), (5, 1), (7, 0)]( x+ _ x& u% Q1 k4 @9 h
print(G1.number_of_nodes()) # 返回顶点的数量 ]. T: M3 P3 c+ v
# 9$ i) s; U! R% \& P
print(G1.number_of_edges()) # 返回边的数量, M$ Q# \; c5 [
# 5
$ ~% g7 N8 V- e" z3 I- `9 E5 `# sprint(G1[10]) # 返回与指定顶点相邻的所有顶点的属性% y* ~6 v! M( {0 r3 I: I+ y
# {0: {'weight': 2.7}, 5: {}}0 t, m; H' D! u, p$ ^) X
print(G1.adj[10]) # 返回与指定顶点相邻的所有顶点的属性
* [! U. [- X( F1 U6 C m" g3 d4 A# {0: {'weight': 2.7}, 5: {}}: k6 `' V0 d# o% k, E" W
print(G1[1][2]) # 返回指定边的属性9 s% k- v2 r/ G9 B
# {'weight': 3.6}. k$ ?' i! v" w- y3 X( l
print(G1.adj[1][2]) # 返回指定边的属性; x: v( T( o" A; r, Z
# {'weight': 3.6}- ]7 q2 _) J2 |. W& \( j
print(G1.degree(10)) # 返回指定顶点的度- J( V- i4 C! ]8 I' F
# 2& H9 ?) ^& h& n4 i9 d
2 G" D- {3 }: p" [- s' S8 \
print('nx.info:',nx.info(G1)) # 返回图的基本信息0 _" q4 {. X8 q1 l8 v7 |
print('nx.degree:',nx.degree(G1)) # 返回图中各顶点的度
$ v$ ~7 O: \8 Hprint('nx.density:',nx.degree_histogram(G1)) # 返回图中度的分布/ R& u6 I8 D) K# P+ k+ F
print('nx.pagerank:',nx.pagerank(G1)) # 返回图中各顶点的频率分布* c3 w; I+ o' o' Q: k, c
+ f c2 K/ p/ X8 l: ]2 [: V8 `
7 f1 o8 H+ H+ _* ^1 w- [
% F' s& f0 s6 Y6 Q n2 p1 [" n
+ u; t( G( `& }! ?! y
: d: O4 ?0 x: b, r1 a7 H; d8 l, f2.3 图的属性和方法图的方法
1 @5 h$ j1 k% f) E3 z
0 W* N9 a- W3 y. S( M; a3 R$ r方法 说明
/ v; I" D: P% Y4 l6 `- Q4 |G.has_node(n) 当图 G 中包括顶点 n 时返回 True6 O2 T8 H, c9 o' ~- M Z+ \9 C
G.has_edge(u, v) 当图 G 中包括边 (u,v) 时返回 True
& D. @3 L, w1 g- i' dG.number_of_nodes() 返回 图 G 中的顶点的数量
$ q; P* B- ~8 O4 d- j! A' ~ j. yG.number_of_edges() 返回 图 G 中的边的数量' q; l: S) b8 D9 X
G.number_of_selfloops() 返回 图 G 中的自循环边的数量
+ r- h2 n1 z! NG.degree([nbunch, weight]) 返回 图 G 中的全部顶点或指定顶点的度
2 \2 U/ G, i2 `! X% qG.selfloop_edges([data, default]) 返回 图 G 中的全部的自循环边
- V9 r7 S, o w+ U0 [* }G.subgraph([nodes]) 从图 G1中抽取顶点[nodes]及对应边构成的子图5 J% {' @$ z% Z
union(G1,G2) 合并图 G1、G2# @: _7 p% N% x+ l+ }% R
nx.info(G) 返回图的基本信息
) S. |. a) b& t, w/ p3 ]3 p& U+ enx.degree(G) 返回图中各顶点的度: B- [# b7 G( c6 {" L# i4 n
nx.degree_histogram(G) 返回图中度的分布
: F2 _: i# ~0 \) Onx.pagerank(G) 返回图中各顶点的频率分布
* r! a+ K5 }0 _: E) E& U8 g/ M" Knx.add_star(G,[nodes],**attr) 向图 G 添加星形网络( e9 B8 s0 }/ l& P6 @- [; t7 G( f
nx.add_path(G,[nodes],**attr) 向图 G 添加一条路径
( h9 I4 X) c: ^8 D+ Nnx.add_cycle(G,[nodes],**attr) 向图 G 添加闭合路径! A1 a8 t! X8 w, p/ }
5 M- u& [/ O, r2 F# o+ j+ k
! m5 D3 H2 D) [7 k例程:" s9 a- \; x: v* }3 d
G1.clear() # 清空图G19 ~3 a$ u) R4 k, _
nx.add_star(G1, [1, 2, 3, 4, 5], weight=1) # 添加星形网络:以第一个顶点为中心
; |, [. J% N% ]" P8 l# [(1, 2), (1, 3), (1, 4), (1, 5)]2 z3 I, W* Z. W
nx.add_path(G1, [5, 6, 8, 9, 10], weight=2) # 添加路径:顺序连接 n个节点的 n-1条边, p, e4 I8 Z o8 A: y" d1 M
# [(5, 6), (6, 8), (8, 9), (9, 10)]
- ~/ [1 k6 ?* ]nx.add_cycle(G1, [7, 8, 9, 10, 12], weight=3) # 添加闭合回路:循环连接 n个节点的 n 条边1 l; N. Y( F' o3 L @) I# G0 ~* v' P
# [(7, 8), (7, 12), (8, 9), (9, 10), (10, 12)]4 t1 C7 R* V- A; K( Y) w
print(G1.nodes) # 返回所有的顶点 [node1,...]
% F8 Q% v* p" gnx.draw_networkx(G1)
% W' Q, S& V" v8 d, xplt.show()
6 n( s( g- p0 X0 ~4 O) ]
5 w O7 Y3 m; W& ZG2 = G1.subgraph([1, 2, 3, 8, 9, 10])
: U- @/ i0 b2 N6 t7 e# fG3 = G1.subgraph([4, 5, 6, 7])
/ S' o# y/ U, J d; p- q8 [G = nx.union(G2, G3)! ]0 v, o- }; D$ g$ n2 ^! q7 {
print(G.nodes) # 返回所有的顶点 [node1,...]
1 M) [3 G: P+ k# [1, 2, 3, 8, 9, 10, 4, 5, 6, 7]2 s2 S4 k l+ v+ h% \6 C. }! {$ g, L
( X- l% f r- w0 v/ W
/ _, v" S7 z* F& C3、图的绘制与分析3.1 图的绘制5 m1 R+ U9 m4 C% X7 E2 u' C# L
可视化是图论和网络问题中很重要的内容。NetworkX 在 Matplotlib、Graphviz 等图形工具包的基础上,提供了丰富的绘图功能。1 F6 Y! @6 g" q4 J
: \) c7 x$ n3 r
本系列拟对图和网络的可视化作一个专题,在此只简单介绍基于 Matplotlib 的基本绘图函数。基本绘图函数使用字典提供的位置将节点放置在散点图上,或者使用布局函数计算位置。
6 a- H# \- |0 }$ m+ k* s. d" W1 }: P" |
方法 说明9 j" |- P. }% Z) N: U
draw(G[,pos,ax]) 基于 Matplotlib 绘制 图 G
3 o8 d* _1 L/ z! Z6 P( ]( a: hdraw_networkx(G[, pos, arrows, with_labels]) 基于 Matplotlib 绘制 图 G
6 p+ H. T) g1 g. s; ndraw_networkx_nodes(G, pos[, nodelist, . . . ]) 绘制图 G 的顶点
b, n- e. H2 u- ~draw_networkx_edges(G, pos[, edgelist, . . . ]) 绘制图 G 的边
, T. J9 s9 i/ Ydraw_networkx_labels(G, pos[, labels, . . . ]) 绘制顶点的标签
l/ N3 a9 q- m. A! p1 r3 [draw_networkx_edge_labels(G, pos[, . . . ]) 绘制边的标签
9 }5 S. O; Z% Z% L5 K# w. Q1 d" K( ^* I6 x
) c- }" y0 Z5 w) ^
其中,nx.draw() 和 nx.draw_networkx() 是最基本的绘图函数,并可以通过自定义函数属性或其它绘图函数设置不同的绘图要求。
" ^5 I; ?0 h2 @$ x9 F Odraw(G, pos=None, ax=None, **kwds) draw_networkx(G, pos=None, arrows=True, with_labels=True, **kwds) ; w+ I! H: s4 M9 K
常用的属性定义如下:( n& I* a/ A* t2 k
" v* z: z3 A$ _( L! o8 G
‘node_size’:指定节点的尺寸大小,默认300" Q6 u+ ^, K9 K. D
‘node_color’:指定节点的颜色,默认红色) O8 J, F" ~ x7 v5 y$ X _
‘node_shape’:节点的形状,默认圆形# Y2 h3 W& Y' {6 w3 v. V4 S
'‘alpha’:透明度,默认1.0,不透明7 P- i, ?1 _' v9 k, Q0 z7 I* ?
‘width’:边的宽度,默认1.05 |! p# }" _' K- Q/ D/ M: O- W: w
‘edge_color’:边的颜色,默认黑色
& ^# I( G9 G8 x$ y‘style’:边的样式,可选 ‘solid’、‘dashed’、‘dotted’、‘dashdot’! O5 Y# k8 V, d3 w( R) R8 ]. M
‘with_labels’:节点是否带标签,默认True, s0 B. h( w) q# l0 T; V
‘font_size’:节点标签字体大小,默认12
" _. K6 r% H- b& U5 K‘font_color’:节点标签字体颜色,默认黑色$ G [; R4 @" i
9 V) \; M+ h( B) [' T5 ?6 J
" n- z m/ Y' J3 ^% f; h# L. Y
3.2 图的分析NetwotkX 提供了图论函数对图的结构进行分析
4 d* j6 b: N# h8 o j# U$ i子图
5 @1 P$ M+ j7 r" i5 }1 b6 y- 子图是指顶点和边都分别是图 G 的顶点的子集和边的子集的图。
- subgraph()方法,按顶点从图 G 中抽出子图。例程如前。$ k! [7 Z4 k/ z* V$ r9 ^6 [
连通子图
1 v6 T! a; O+ w2 ~$ L1 ~2 K; F
7 C( ]( P4 e$ J" n- 如果图 G 中的任意两点间相互连通,则 G 是连通图。
- [color=rgba(0, 0, 0, 0.749019607843137)]connected_components()方法,返回连通子图的集合。
8 \7 ]" p* {1 M# y; N) {[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}]' S3 R* E! g+ U
% x& T" G2 G7 Y* u4 i6 S T$ D, x6 x' v; k
' x6 U5 M8 G" F ]7 C
/ A* o0 `, H% x' H
|