Python小白的数学建模课-图论的基本概念& l/ L& H6 i9 P) K+ @3 x+ B* `; b
: W& u \4 T2 R# V0 Z l3 x7 v8 \- 图论中所说的图,不是图形图像或地图,而是指由顶点和边所构成的图形结构。
- 图论不仅与拓扑学、计算机数据结构和算法密切相关,而且正在成为机器学习的关键技术。
- 本系列结合数学建模的应用需求,来介绍 NetworkX 图论与复杂网络工具包的基本功能和典型算法。
9 ~; q1 z6 @; T$ k2 g& U5 C# W* y 6 e6 c8 |9 }1 z$ k' V
1. 图论1.1 图论是什么$ g7 \/ l$ G7 R6 L2 |& t2 [! B( O
图论〔Graph Theory〕以图为研究对象,是离散数学的重要内容。图论不仅与拓扑学、计算机数据结构和算法密切相关,而且正在成为机器学习的关键技术。
2 v7 X+ n. |4 y+ S3 Y, u+ c
2 [* b: w5 u2 e6 i2 O3 a图论中所说的图,不是指图形图像(image)或地图(map),而是指由顶点(vertex)和连接顶点的边(edge)所构成的关系结构。
; ^$ [; u g n7 G( j! H" ]' H% h. H4 S
图提供了一种处理关系和交互等抽象概念的更好的方法,它还提供了直观的视觉方式来思考这些概念。
5 c' I+ a3 L9 }7 M8 q0 } J; c4 T; M) w# o; Y8 a N
1.2 NetworkX 工具包- Q* b6 {( `% t# k7 z
NetworkX 是基于 Python 语言的图论与复杂网络工具包,用于创建、操作和研究复杂网络的结构、动力学和功能。
& ~0 C. R( g/ U. u. H- B# e+ G1 O1 \# M/ ]4 o
NetworkX 可以以标准和非标准的数据格式描述图与网络,生成图与网络,分析网络结构,构建网络模型,设计网络算法,绘制网络图形。
! F r+ v0 I, [0 E0 n* `
$ @% ^# Q3 f& X$ \ gNetworkX 提供了图形的类、对象、图形生成器、网络生成器、绘图工具,内置了常用的图论和网络分析算法,可以进行图和网络的建模、分析和仿真。( j$ Z7 t, N7 Z7 x
+ m H: f7 @5 t( E8 _8 w; ^- t1 VNetworkX 的功能非常强大和庞杂,所涉及内容远远、远远地超出了数学建模的范围,甚至于很难进行系统的概括。本系列结合数学建模的应用需求,来介绍 NetworkX 图论与复杂网络工具包的基本功能和典型算法。0 m$ _1 w% P* ~1 K- @# Z* }
9 S \" I* W4 R2 a ) [3 {) X7 Y% R. d8 g+ A9 e
2、图、顶点和边的创建与基本操作5 Q+ S5 v; o, B9 ^9 H
图由顶点和连接顶点的边构成,但与顶点的位置、边的曲直长短无关。 Networkx 支持创建简单无向图、有向图和多重图;内置许多标准的图论算法,节点可为任意数据;支持任意的边值维度,功能丰富,简单易用。 2.1 图的基本概念
4 o/ \ h- |. X图(Graph):图是由若干顶点和连接顶点的边所构成关系结构。/ S1 h, S% ^. `$ e% T: u5 H
顶点(Node):图中的点称为顶点,也称节点。5 I: d" Q( @$ ~/ t
边(Edge):顶点之间的连线,称为边。8 x6 ?# d- n4 Z
平行边(Parallel edge):起点相同、终点也相同的两条边称为平行边。1 B, Q; \5 _/ ?
循环(Cycle):起点和终点重合的边称为循环。/ b& _9 b, n, n- U
有向图(Digraph):图中的每条边都带有方向,称为有向图。6 A0 H4 a' j/ Y8 `- a) i9 k( r4 W u
无向图(Undirected graph):图中的每条边都没有方向,称为无向图。
4 e! ?. S( e, K$ V$ L& Q赋权图(Weighted graph):图中的每条边都有一个或多个对应的参数,称为赋权图。该参数称为这条边的权,权可以用来表示两点间的距离、时间、费用。6 T; H- t% U& f& B. z6 @* K
度(Degree):与顶点相连的边的数量,称为该顶点的度。/ k2 g3 W2 N4 F7 z" w E# c
, I, Z$ @% f1 t: N9 y3 |2.2 图、顶点和边的操作' R% g' q' d: j5 o
Networkx很容易创建图、向图中添加顶点和边、从图中删除顶点和边,也可以查看、删除顶点和边的属性。, G+ b' v+ o5 Y3 E0 k! a3 w1 o8 J
3 o& e) h4 L* K* e2.2.1 图的创建Graph() 类、DiGraph() 类、MultiGraph() 类和 MultiDiGraph() 类分别用来创建:无向图、有向图、多图和有向多图。定义和例程如下:
% e" D. l# Q( q" m( v. |5 g' W5 r
class Graph(incoming_graph_data=None, **attr)- C* }, `8 V% E; T( h5 i
import networkx as nx # 导入 NetworkX 工具包
, j6 \2 B3 L* Y
# E* G6 v! s# v# 创建 图3 V! p, Y7 s: G
G1 = nx.Graph() # 创建:空的 无向图$ L; t# ?7 j, P$ X5 J c
G2 = nx.DiGraph() #创建:空的 有向图
" B0 ?6 f4 H8 ?4 E1 ~G3 = nx.MultiGraph() #创建:空的 多图
3 \7 A# H- w# m/ g; I) x9 M0 ~G4 = nx.MultiDiGraph() #创建:空的 有向多图0 w. T1 R. |; g+ b
/ S2 V% J t; k& D- O) Z/ [. H% `8 r% `3 y. H$ T
2.2.2 顶点的添加、删除和查看
! ^ H0 z: s& [9 D- s: c图的每个顶点都有唯一的标签属性(label),可以用整数或字符类型表示,顶点还可以自定义任意属性。 顶点的常用操作:添加顶点,删除顶点,定义顶点属性,查看顶点和顶点属性。定义和例程如下: # f+ R& E* C& }
Graph.add_node(node_for_adding, **attr)) {- O+ u2 j: L7 s- |
Graph.add_nodes_from(nodes_for_adding, **attr), |$ Z7 c6 Q& b: V( i6 X w0 a: z) m
Graph.remove_node(n): d, l/ d L. \
Graph.remove_nodes_from(nodes)8 e# ?3 w: ?2 W1 Q8 N7 L
4 o! k2 ~5 R7 F3 ]
# 顶点(node)的操作
1 v) h3 \$ ~! M0 V4 O1 W# 向图中添加顶点/ [. g5 ~5 s x
G1.add_node(1) # 向 G1 添加顶点 1& |8 b. U# U: r4 n! U
G1.add_node(1, name='n1', weight=1.0) # 添加顶点 1,定义 name, weight 属性6 \" A6 V; w8 S/ @0 V0 b
G1.add_node(2, date='May-16') # 添加顶点 2,定义 time 属性0 w N, W7 [( y, V6 N" ?7 Z
G1.add_nodes_from([3, 0, 6], dist=1) # 添加多个顶点,并定义属性4 a, D! p, K) P* j! t6 w
G1.add_nodes_from(range(10, 15)) # 向图 G1 添加顶点 10~14, o- ]0 H4 |+ u) G$ `& f, G0 s
2 e$ P4 | j5 y* ?+ [0 q- k5 P
# 查看顶点和顶点属性
( O* {. s) r" y5 z. ]" [print(G1.nodes()) # 查看顶点列表( t1 F8 E- `) c3 [
# [1, 2, 3, 0, 6, 10, 11, 12, 13, 14]9 h$ J: h9 z% o/ T. ~
print(G1._node) # 查看顶点属性
; h+ `+ p b" @3 _% L# {1: {'name': 'n1', 'weight': 1.0}, 2: {'date': 'May-16'}, 3: {'dist': 1}, 0: {'dist': 1}, 6: {'dist': 1}, 10: {}, 11: {}, 12: {}, 13: {}, 14: {}}
+ X. Q$ N/ S0 M" t9 f" s( r! G# X! G1 h* ?! \ |$ ~
# 从图中删除顶点1 b- i+ s* ~) O% d# V$ P ?$ [
G1.remove_node(1) # 删除顶点
+ S( q6 P. ^" @* ?+ TG1.remove_nodes_from([1, 11, 13, 14]) # 通过顶点标签的 list 删除多个顶点
% {: K) W; p \$ N/ kprint(G1.nodes()) # 查看顶点. {/ f2 W$ ?1 }9 _; k* p: Y
# [2, 3, 0, 6, 10, 12] # 顶点列表
. w' p, I2 t* c( j# V; P; G; \2.2.3 边的添加、删除和查看边是两个顶点之间的连接,在 NetworkX 中 边是由对应顶点的名字的元组组成 e=(node1,node2)。边可以设置权重、关系等属性。 边的常用操作:添加边,删除边,定义边的属性,查看边和边的属性。向图中添加边时,如果边的顶点是图中不存在的,则自动向图中添加该顶点。 Graph.add_edge(u_of_edge, v_of_edge, **attr)* o" x1 h, A' J% s& m# P
Graph.add_edges_from(ebunch_to_add, **attr)
# D1 B8 D, J) ~) TGraph.add_weighted_edges_from(ebunch_to_add, weight=‘weight’, **attr)7 p* d4 A* h- q' t2 w: L7 b9 S
8 Y& L+ V$ W% J* F# 边(edge)的操作+ C$ {$ F) t0 Y& D5 b8 Q
# 向图中添加边! d: J" H+ D. h8 I1 G: K
G1.add_edge(1,5) # 向 G1 添加边,并自动添加图中没有的顶点3 l6 @ O/ G9 E, t8 V1 M* n* q
G1.add_edge(0,10, weight=2.7) # 向 G1 添加边,并设置边的属性
5 E- i! b+ j, ]: RG1.add_edges_from([(1,2,{'weight':0}), (2,3,{'color':'blue'})]) # 向图中添加边,并设置属性* o5 d, S P% O O$ _8 b3 s( n! N A' Y
G1.add_edges_from([(3,6),(1,2),(6,7),(5,10),(0,1)]) # 向图中添加多条边
. ~0 S1 t' K5 W0 k# ~G1.add_weighted_edges_from([(1,2,3.6),[6,12,0.5]]) # 向图中添加多条赋权边: (node1,node2,weight)& T7 z" Z4 c; C+ ]0 B
print(G1.nodes()) # 查看顶点& W1 c" t* F5 I
# [2, 3, 0, 6, 10, 12, 1, 5, 7] # 自动添加了图中没有的顶点
, q' j: V0 g% ` f% k& K
4 ^5 X, R4 y# v; h5 _# 从图中删除边
3 y8 v+ }, c3 D7 {. _/ q( }8 mG1.remove_edge(0,1) # 从图中删除边 0-14 e' t3 T+ z3 `; \
G1.remove_edges_from([(2,3),(1,5),(6,7)]) # 从图中删除多条边
+ Q" T' Z/ I; Z+ ^% M3 |0 C. y) D9 e' o, o; K4 L0 h+ ?" P
# 查看 边和边的属性
. G& J: o% G9 s! I; I. o/ I2 Vprint(G1.edges) # 查看所有的边/ q4 ^! ]1 e, P7 c
[(2, 1), (3, 6), (0, 10), (6, 12), (10, 5)]7 B. Q8 `6 m! x8 S% u5 P/ V3 M
print(G1.get_edge_data(1,2)) # 查看指定边的属性
* O3 J) H% U! S/ B# {'weight': 3.6}: i2 y( E0 u [
print(G1[1][2]) # 查看指定边的属性
4 b+ S0 u0 @5 C7 V3 o q4 C# {'weight': 3.6}, w8 [' D& B; `* q
print(G1.edges(data=True)) # 查看所有边的属性
' r2 a, V4 |6 N/ W5 Z( E# [(2, 1, {'weight': 3.6}), (3, 6, {}), (0, 10, {'weight': 2.7}), (6, 12, {'weight': 0.5}), (10, 5, {})]
' Z* o/ C% c# e+ _- d
3 Q- k# _5 _ ]3 D# u! N) o2.2.4 查看图、顶点和边的信息
$ g3 O: f3 n) B S. D7 I' x; x
* q3 M/ a- d) t4 H0 f. F9 D# 查看图、顶点和边的信息2 [1 T2 K2 H/ D
print(G1.nodes) # 返回所有的顶点 [node1,...]
# P! Z1 R T e. j6 c t: P# [2, 3, 0, 6, 10, 12, 1, 5, 7]! U2 v2 ?% ?: D
print(G1.edges) # 返回所有的边 [(node1,node2),...]
! D% v: Y. I; K# A# \. e# [(2, 1), (3, 6), (0, 10), (6, 12), (10, 5)]
( V; C2 k/ H/ X# b3 g8 M' jprint(G1.degree) # 返回各顶点的度 [(node1,degree1),...]% F5 q# \- |; h2 j
# [(2, 1), (3, 1), (0, 1), (6, 2), (10, 2), (12, 1), (1, 1), (5, 1), (7, 0)]
" p( D! Y' N/ E- ~3 e' A2 m1 `print(G1.number_of_nodes()) # 返回顶点的数量. M& N$ L+ |+ o
# 9
2 d6 k- b F( u* r5 j! tprint(G1.number_of_edges()) # 返回边的数量( J% d# L2 W: D
# 5( H6 z& F8 c7 ?4 O, n! Q; z
print(G1[10]) # 返回与指定顶点相邻的所有顶点的属性
2 l3 w% D+ \) j* {' A- J2 }8 C# {0: {'weight': 2.7}, 5: {}}3 _$ v* L. b" W* Y X- A- l
print(G1.adj[10]) # 返回与指定顶点相邻的所有顶点的属性
2 d5 F" h0 K) H% a; y; |8 Y9 [# {0: {'weight': 2.7}, 5: {}}
" J: v9 E1 t6 Aprint(G1[1][2]) # 返回指定边的属性
' {7 t ~' M) O9 V, M! q! ?# {'weight': 3.6}9 d, ~7 [: I4 [: s O0 D
print(G1.adj[1][2]) # 返回指定边的属性; t4 f7 h3 b) s4 o7 I' o& v) z; l6 e
# {'weight': 3.6}/ M, ~4 r1 o. W) m2 Z7 [
print(G1.degree(10)) # 返回指定顶点的度& p- J# T7 q& K; d
# 2
( c e" e5 u' e- z+ X* h% i1 o# }+ \. _
print('nx.info:',nx.info(G1)) # 返回图的基本信息- V: L$ T9 e; k4 R0 [
print('nx.degree:',nx.degree(G1)) # 返回图中各顶点的度5 i. N( d3 }% _; q M' K
print('nx.density:',nx.degree_histogram(G1)) # 返回图中度的分布
3 X5 B& ]+ J8 ?* C& k- f4 Lprint('nx.pagerank:',nx.pagerank(G1)) # 返回图中各顶点的频率分布: w" n) q' S9 \8 Z
4 F% Z4 R0 j. e7 y+ T- v) c5 D$ M9 D
, o( a& j1 H1 q" K& J O6 G! ^: Y
, o8 y' A* k. o9 z$ f# _3 p r
1 m% u5 u/ a9 l6 {2.3 图的属性和方法图的方法
* f9 `& I; |; k; k {5 t) X Z
方法 说明* }: [8 {$ K. N) i5 C' T
G.has_node(n) 当图 G 中包括顶点 n 时返回 True4 {, z2 F* a/ B; X; E
G.has_edge(u, v) 当图 G 中包括边 (u,v) 时返回 True
" S$ G! O; t8 U5 S8 J, eG.number_of_nodes() 返回 图 G 中的顶点的数量0 i- K4 h2 G# H0 ~! D* W1 t
G.number_of_edges() 返回 图 G 中的边的数量
4 }# B1 d6 W4 k; ^( kG.number_of_selfloops() 返回 图 G 中的自循环边的数量. g/ S! E4 S d$ Z' _9 W! x
G.degree([nbunch, weight]) 返回 图 G 中的全部顶点或指定顶点的度
; D4 J3 }8 ]$ H _# p! o; oG.selfloop_edges([data, default]) 返回 图 G 中的全部的自循环边( z# L$ U5 o- W+ q: K
G.subgraph([nodes]) 从图 G1中抽取顶点[nodes]及对应边构成的子图
7 a6 D1 T: b4 k% J# k2 y5 Hunion(G1,G2) 合并图 G1、G2
. C+ g6 f) [, x+ U# {nx.info(G) 返回图的基本信息/ o0 k4 A0 r5 B1 x# B. M
nx.degree(G) 返回图中各顶点的度! `3 W7 \! {2 V. h
nx.degree_histogram(G) 返回图中度的分布( o7 b8 T- M6 O+ G! k- t6 m+ x) c
nx.pagerank(G) 返回图中各顶点的频率分布
v' r' ^3 p* p6 l% Jnx.add_star(G,[nodes],**attr) 向图 G 添加星形网络
) H" G# c' Y+ ~3 S2 x# l$ a( c$ mnx.add_path(G,[nodes],**attr) 向图 G 添加一条路径
# c D+ L, j# Z/ Q" B; E0 @nx.add_cycle(G,[nodes],**attr) 向图 G 添加闭合路径0 |6 p* f" ~& c" b6 I8 J
. F8 Z: f$ t: e! z
6 K; g. C% M2 ^* |- C# R
例程:2 I' K. d* Q! n0 }$ B( Q
G1.clear() # 清空图G1
5 m) e, o# L8 h5 p0 d+ b bnx.add_star(G1, [1, 2, 3, 4, 5], weight=1) # 添加星形网络:以第一个顶点为中心
( {# @; f2 Z. k0 [ I# [(1, 2), (1, 3), (1, 4), (1, 5)]
Y: D( C8 G7 ]) l1 M1 H$ Unx.add_path(G1, [5, 6, 8, 9, 10], weight=2) # 添加路径:顺序连接 n个节点的 n-1条边" } ?" X/ a! U+ O
# [(5, 6), (6, 8), (8, 9), (9, 10)]8 J' \# i3 Z& B' ]! D" ]1 z) A
nx.add_cycle(G1, [7, 8, 9, 10, 12], weight=3) # 添加闭合回路:循环连接 n个节点的 n 条边4 Z- H% \+ c5 h% c3 E
# [(7, 8), (7, 12), (8, 9), (9, 10), (10, 12)]
" M0 b% x2 Q2 y1 o# b0 W; H% oprint(G1.nodes) # 返回所有的顶点 [node1,...]; l% M5 A2 i+ }' j: C0 ]
nx.draw_networkx(G1)# F2 k) |+ N: e, Z+ M( u$ M3 S5 k
plt.show()2 H3 V6 g d: G9 i) m
& B# y2 h( {* n8 K+ DG2 = G1.subgraph([1, 2, 3, 8, 9, 10])
, M! H. ~( y- @0 HG3 = G1.subgraph([4, 5, 6, 7])
h9 M k2 G4 d# I% O* E+ TG = nx.union(G2, G3)3 L2 b% V. y' \9 |; {
print(G.nodes) # 返回所有的顶点 [node1,...]- H" V) w# X" X, e' G8 s) h* q
# [1, 2, 3, 8, 9, 10, 4, 5, 6, 7]
$ ^5 Q( g' K& t# U& L
?7 z, ^: n6 x! V
+ N/ Q# J7 d/ v7 q2 C3、图的绘制与分析3.1 图的绘制8 e' ? K$ E0 c/ `
可视化是图论和网络问题中很重要的内容。NetworkX 在 Matplotlib、Graphviz 等图形工具包的基础上,提供了丰富的绘图功能。* X) K3 P% x7 @) k9 Z) Y
& b; Z- F$ A) Y9 ^# k+ K* X- E8 ^, O本系列拟对图和网络的可视化作一个专题,在此只简单介绍基于 Matplotlib 的基本绘图函数。基本绘图函数使用字典提供的位置将节点放置在散点图上,或者使用布局函数计算位置。
3 c+ a: \3 n& Q% v4 h( @- s% S4 c! q7 J+ j* g& a
方法 说明
) }, a! ]/ m9 D% Adraw(G[,pos,ax]) 基于 Matplotlib 绘制 图 G
S, o& [) s% j3 P, m; tdraw_networkx(G[, pos, arrows, with_labels]) 基于 Matplotlib 绘制 图 G/ z" |1 c) ?& N. @5 g
draw_networkx_nodes(G, pos[, nodelist, . . . ]) 绘制图 G 的顶点
3 n |1 Z9 G) v5 @( T# n; Adraw_networkx_edges(G, pos[, edgelist, . . . ]) 绘制图 G 的边 R) S1 T5 [! L- C
draw_networkx_labels(G, pos[, labels, . . . ]) 绘制顶点的标签* z5 d1 V0 C) m+ P
draw_networkx_edge_labels(G, pos[, . . . ]) 绘制边的标签
+ _ g" C, n1 u. h, R
9 U) E. H% }2 j# I$ A& \
( X1 g0 O1 W; A- x# w其中,nx.draw() 和 nx.draw_networkx() 是最基本的绘图函数,并可以通过自定义函数属性或其它绘图函数设置不同的绘图要求。
) B9 o! L" h5 v# b' udraw(G, pos=None, ax=None, **kwds) draw_networkx(G, pos=None, arrows=True, with_labels=True, **kwds) $ A8 E" v9 H9 o- V3 m2 A" c
常用的属性定义如下:
& c! m/ c6 |4 O1 s1 \; _' m4 O: ]4 q& Q
‘node_size’:指定节点的尺寸大小,默认3003 d$ b! T: h# Z' e1 X) o
‘node_color’:指定节点的颜色,默认红色
1 R! P! Q/ X& D3 e) A‘node_shape’:节点的形状,默认圆形* X! r# D& W4 x9 M1 P* r
'‘alpha’:透明度,默认1.0,不透明
1 G7 y8 l4 I+ G2 y* ]/ T& |; w‘width’:边的宽度,默认1.02 e5 @$ }8 e' M4 L7 \
‘edge_color’:边的颜色,默认黑色
: ^/ z% h M( a5 r5 G1 _% ]‘style’:边的样式,可选 ‘solid’、‘dashed’、‘dotted’、‘dashdot’/ K D9 Q7 ?6 s3 B! T
‘with_labels’:节点是否带标签,默认True2 ]4 s' _! L( Y: M9 `
‘font_size’:节点标签字体大小,默认126 j; L; W% c/ a1 w+ L" W1 h, [0 p2 R% a
‘font_color’:节点标签字体颜色,默认黑色; u1 ?9 }# d1 ?, d) G
+ J$ U5 p6 [ c: r' |
1 p& Y( T4 U, R0 m6 P
3.2 图的分析NetwotkX 提供了图论函数对图的结构进行分析. W, d6 J4 A5 m
子图3 K* W1 T0 z* d5 d. }7 H1 N0 E/ B
- 子图是指顶点和边都分别是图 G 的顶点的子集和边的子集的图。
- subgraph()方法,按顶点从图 G 中抽出子图。例程如前。, @* \9 }& e# g9 G* d
连通子图5 o8 z# v3 `* ~6 ]5 ]. _
# v: k8 |/ c' k" r9 `9 A3 c
- 如果图 G 中的任意两点间相互连通,则 G 是连通图。
- [color=rgba(0, 0, 0, 0.749019607843137)]connected_components()方法,返回连通子图的集合。" z/ K" }6 G' ~+ S" G
[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}]
5 }; U6 d3 O7 |
: ^8 n8 n; X* V6 c2 u& C+ Q4 y/ E. P: A9 r& u% T
7 r; w* \+ Z0 K* \
% g2 }6 Y* d3 b8 _0 E; J1 n ^ K
|