Python小白的数学建模课-图论的基本概念+ v' ^/ K; V+ b' k, [$ U
) x, o4 S7 S4 M0 }
- 图论中所说的图,不是图形图像或地图,而是指由顶点和边所构成的图形结构。
- 图论不仅与拓扑学、计算机数据结构和算法密切相关,而且正在成为机器学习的关键技术。
- 本系列结合数学建模的应用需求,来介绍 NetworkX 图论与复杂网络工具包的基本功能和典型算法。4 G Y7 B' A/ S/ C S/ F! g7 u7 Q
( O% T3 A% v/ W7 s7 S1. 图论1.1 图论是什么
; Y* W; ^) A9 p% ]+ A图论〔Graph Theory〕以图为研究对象,是离散数学的重要内容。图论不仅与拓扑学、计算机数据结构和算法密切相关,而且正在成为机器学习的关键技术。
& b8 d! B; a- T, z0 q# j$ `
% S# q$ ]5 z5 T2 P- F图论中所说的图,不是指图形图像(image)或地图(map),而是指由顶点(vertex)和连接顶点的边(edge)所构成的关系结构。+ }3 d$ {( D, q6 {
5 D, s: j. I6 |+ @3 c图提供了一种处理关系和交互等抽象概念的更好的方法,它还提供了直观的视觉方式来思考这些概念。- v2 u4 U5 W+ b& B7 a+ |& h6 Z
& L% H, J) r+ v" \1.2 NetworkX 工具包
9 U3 C- j: s( ~" P7 k% PNetworkX 是基于 Python 语言的图论与复杂网络工具包,用于创建、操作和研究复杂网络的结构、动力学和功能。( N) Y3 S+ ]) L) ~3 U
, G: w$ `! e! v: L
NetworkX 可以以标准和非标准的数据格式描述图与网络,生成图与网络,分析网络结构,构建网络模型,设计网络算法,绘制网络图形。- L. U3 ]1 H! l4 j
, M/ w; n! k: @; |- X6 M' mNetworkX 提供了图形的类、对象、图形生成器、网络生成器、绘图工具,内置了常用的图论和网络分析算法,可以进行图和网络的建模、分析和仿真。) L2 V- t+ g; i0 _
; R+ r4 _% ^7 W% K: v* _
NetworkX 的功能非常强大和庞杂,所涉及内容远远、远远地超出了数学建模的范围,甚至于很难进行系统的概括。本系列结合数学建模的应用需求,来介绍 NetworkX 图论与复杂网络工具包的基本功能和典型算法。
/ d: N1 x2 s" U, G( {. t* q7 Z( I* F6 l3 M
f6 ~ A6 E7 o* W' c/ h$ E
2、图、顶点和边的创建与基本操作
4 ~, B$ S7 l7 O! H Q图由顶点和连接顶点的边构成,但与顶点的位置、边的曲直长短无关。 Networkx 支持创建简单无向图、有向图和多重图;内置许多标准的图论算法,节点可为任意数据;支持任意的边值维度,功能丰富,简单易用。 2.1 图的基本概念2 ]% H- g- f0 K. w; T' H
图(Graph):图是由若干顶点和连接顶点的边所构成关系结构。
! k) i1 m$ r. T6 p5 Y) E顶点(Node):图中的点称为顶点,也称节点。
& y$ w9 t8 y0 G: d# t" ~3 q' U边(Edge):顶点之间的连线,称为边。 ~ p, W. k' R8 k" s
平行边(Parallel edge):起点相同、终点也相同的两条边称为平行边。4 e2 T8 a9 z7 {
循环(Cycle):起点和终点重合的边称为循环。0 B% N; V9 {7 \8 t9 L# T& ?
有向图(Digraph):图中的每条边都带有方向,称为有向图。0 }, v0 d, j9 H( T
无向图(Undirected graph):图中的每条边都没有方向,称为无向图。 j4 |; y2 e( P# O3 A! X
赋权图(Weighted graph):图中的每条边都有一个或多个对应的参数,称为赋权图。该参数称为这条边的权,权可以用来表示两点间的距离、时间、费用。' `% |+ w3 u# s& ]/ _' g/ g
度(Degree):与顶点相连的边的数量,称为该顶点的度。
: G9 [7 V. [- d/ H& \: a. }) e3 s& o" X0 Z% y' l4 m- E
2.2 图、顶点和边的操作2 k, Q0 f( _3 K$ Y
Networkx很容易创建图、向图中添加顶点和边、从图中删除顶点和边,也可以查看、删除顶点和边的属性。
* i' |7 e2 H0 m/ y: }- ~9 H6 L6 D; x! p# B8 j* h
2.2.1 图的创建Graph() 类、DiGraph() 类、MultiGraph() 类和 MultiDiGraph() 类分别用来创建:无向图、有向图、多图和有向多图。定义和例程如下:
/ I3 e& s- n1 U5 Y, m9 G A( S) V% D& G
class Graph(incoming_graph_data=None, **attr)5 c. ? d* v z$ d
import networkx as nx # 导入 NetworkX 工具包+ g" w: m0 f' y# q: Z" `
$ }) ?" o( O2 u5 X
# 创建 图; e' f; H0 I. \# R
G1 = nx.Graph() # 创建:空的 无向图
# t# L$ C6 h! g3 d5 h; n( RG2 = nx.DiGraph() #创建:空的 有向图
, F4 A/ T* L' \# F% o4 B" }G3 = nx.MultiGraph() #创建:空的 多图
. ]/ ^: E4 \) O# z" Z: d6 |G4 = nx.MultiDiGraph() #创建:空的 有向多图
( Z2 T1 B2 Y3 ]/ v/ X+ Z! K- _
' l: W- _' G/ k G/ W
2.2.2 顶点的添加、删除和查看
, m5 a- A2 y6 q+ c图的每个顶点都有唯一的标签属性(label),可以用整数或字符类型表示,顶点还可以自定义任意属性。 顶点的常用操作:添加顶点,删除顶点,定义顶点属性,查看顶点和顶点属性。定义和例程如下:
! z, ^3 b2 {6 \% o( |8 B: DGraph.add_node(node_for_adding, **attr)( R9 S5 q( K1 |9 |
Graph.add_nodes_from(nodes_for_adding, **attr)
9 V" e/ w. r8 H8 v' x( t# mGraph.remove_node(n)# H( Y2 J% U* b; g' ~: M* z
Graph.remove_nodes_from(nodes)
5 |3 Y! A m) I5 `, m& G. {" b% U q+ q8 {( J
# 顶点(node)的操作
" ^, G; \% i* m% A# 向图中添加顶点6 c6 g, w8 y5 o2 y9 j4 Y2 W
G1.add_node(1) # 向 G1 添加顶点 1
3 c0 U( Z: R4 ?$ eG1.add_node(1, name='n1', weight=1.0) # 添加顶点 1,定义 name, weight 属性
) e4 E6 L: M3 n" r" ZG1.add_node(2, date='May-16') # 添加顶点 2,定义 time 属性
$ Y/ n W! i& c( G# |G1.add_nodes_from([3, 0, 6], dist=1) # 添加多个顶点,并定义属性8 B& g* ~" @7 E; t+ e1 Z3 _4 p
G1.add_nodes_from(range(10, 15)) # 向图 G1 添加顶点 10~14
) P* W# r7 T2 j: r7 j! R2 n6 n0 [( f9 \( i7 n1 k+ k
# 查看顶点和顶点属性3 h7 Y* R; q8 T M; ?6 Z
print(G1.nodes()) # 查看顶点列表6 O9 Y- L; F, J: u4 T6 G2 i
# [1, 2, 3, 0, 6, 10, 11, 12, 13, 14]
2 I) \6 \! z; _# l0 Gprint(G1._node) # 查看顶点属性
- x4 {/ f7 S/ i9 i/ D- X: i# {1: {'name': 'n1', 'weight': 1.0}, 2: {'date': 'May-16'}, 3: {'dist': 1}, 0: {'dist': 1}, 6: {'dist': 1}, 10: {}, 11: {}, 12: {}, 13: {}, 14: {}}
* f6 a6 t' j* ^! G* A
; ] J1 k. X: b! X$ _# 从图中删除顶点
- {. k7 W- e7 B- KG1.remove_node(1) # 删除顶点
5 X8 z* B9 k/ ^9 j2 PG1.remove_nodes_from([1, 11, 13, 14]) # 通过顶点标签的 list 删除多个顶点6 M$ |5 N! B% S. f
print(G1.nodes()) # 查看顶点
; D* s, F+ m, J! O. F( @# [2, 3, 0, 6, 10, 12] # 顶点列表1 q& Q& O7 q6 A
2.2.3 边的添加、删除和查看边是两个顶点之间的连接,在 NetworkX 中 边是由对应顶点的名字的元组组成 e=(node1,node2)。边可以设置权重、关系等属性。 边的常用操作:添加边,删除边,定义边的属性,查看边和边的属性。向图中添加边时,如果边的顶点是图中不存在的,则自动向图中添加该顶点。 Graph.add_edge(u_of_edge, v_of_edge, **attr) C3 d0 H( o* i& p; b
Graph.add_edges_from(ebunch_to_add, **attr)
5 V2 {" g1 |' G" l q. o; R& ^$ kGraph.add_weighted_edges_from(ebunch_to_add, weight=‘weight’, **attr)
7 A2 s# a* U( J
; y0 F, ?& ?/ Q. R: h5 t! a# 边(edge)的操作
. [" Q, R/ @3 E1 M2 ~# H# 向图中添加边
" m7 s9 c" l5 g* q9 R! v5 AG1.add_edge(1,5) # 向 G1 添加边,并自动添加图中没有的顶点5 [- h: n Z2 e# t2 I& S; W
G1.add_edge(0,10, weight=2.7) # 向 G1 添加边,并设置边的属性" P; F1 ?6 A0 W4 F9 ^- T
G1.add_edges_from([(1,2,{'weight':0}), (2,3,{'color':'blue'})]) # 向图中添加边,并设置属性
: c" N' `# x5 J/ A- Y, EG1.add_edges_from([(3,6),(1,2),(6,7),(5,10),(0,1)]) # 向图中添加多条边. l2 W9 G; G, e" i# m
G1.add_weighted_edges_from([(1,2,3.6),[6,12,0.5]]) # 向图中添加多条赋权边: (node1,node2,weight)6 z, r% Z, S5 G) [! ^
print(G1.nodes()) # 查看顶点9 ^% ?& `& I3 `/ D, E
# [2, 3, 0, 6, 10, 12, 1, 5, 7] # 自动添加了图中没有的顶点
8 g7 j" y' l) r }& {' }! D$ R4 Y q+ ?0 c# [0 p2 j
# 从图中删除边4 n4 {; _- C! ? x$ g0 ~4 C7 t
G1.remove_edge(0,1) # 从图中删除边 0-1
1 T) J" f; w2 l; u0 }( X( g! kG1.remove_edges_from([(2,3),(1,5),(6,7)]) # 从图中删除多条边 v' a+ q, `( K7 @8 F: L: o" x
" y6 m _; n5 P% s5 d* k# 查看 边和边的属性, F0 a+ q/ Y9 w( n8 {- \
print(G1.edges) # 查看所有的边
* a& H, s/ }7 ~9 Q[(2, 1), (3, 6), (0, 10), (6, 12), (10, 5)]
' P! b- U' a @5 m" bprint(G1.get_edge_data(1,2)) # 查看指定边的属性) G+ b; q6 i% ` B
# {'weight': 3.6}! R3 E, g* Z7 b/ Y" q2 J5 O
print(G1[1][2]) # 查看指定边的属性
) k; m& B j. T# t9 l1 N9 ]# {'weight': 3.6}
8 |: {: R9 D4 J W: o" o3 iprint(G1.edges(data=True)) # 查看所有边的属性. M, @3 V3 ]% f" _0 Y( k1 `
# [(2, 1, {'weight': 3.6}), (3, 6, {}), (0, 10, {'weight': 2.7}), (6, 12, {'weight': 0.5}), (10, 5, {})]
& i6 X" H, u8 `2 N
4 H F8 m& c8 |( s. m2.2.4 查看图、顶点和边的信息0 L$ N m1 |4 u; Y
1 G+ O* U/ j4 N# h# 查看图、顶点和边的信息
+ A6 A2 P$ ^9 X4 F$ s( R; mprint(G1.nodes) # 返回所有的顶点 [node1,...]
4 ]) e9 r0 p- D \3 G3 T& {# [2, 3, 0, 6, 10, 12, 1, 5, 7]4 X1 {% Q9 T7 Y! }; r
print(G1.edges) # 返回所有的边 [(node1,node2),...]' `! p1 L$ h8 D4 N. z
# [(2, 1), (3, 6), (0, 10), (6, 12), (10, 5)]8 S+ r- R1 w( X7 i# t: h& N
print(G1.degree) # 返回各顶点的度 [(node1,degree1),...]- Y6 @- T Q- z. \. \
# [(2, 1), (3, 1), (0, 1), (6, 2), (10, 2), (12, 1), (1, 1), (5, 1), (7, 0)], i) R0 f- s/ L0 x: ~
print(G1.number_of_nodes()) # 返回顶点的数量. c# ? M1 `8 s" N. J
# 93 o8 ~3 v( t |+ H( \. ^
print(G1.number_of_edges()) # 返回边的数量
: p$ d1 Q2 C! ]9 M& d5 `2 T# 5+ }& U( p9 a: j* u
print(G1[10]) # 返回与指定顶点相邻的所有顶点的属性
" s( e+ z/ T% v! @' P: p0 ~# {0: {'weight': 2.7}, 5: {}}
/ I; k( x% k/ ^* [print(G1.adj[10]) # 返回与指定顶点相邻的所有顶点的属性0 V5 |/ U( V1 r" x/ V7 u6 Z4 ]% |) ?
# {0: {'weight': 2.7}, 5: {}}& h8 e: L, Q8 P' G& x! [! ~! x
print(G1[1][2]) # 返回指定边的属性
: h$ V3 k/ f, L* ~8 K* f# {'weight': 3.6} g' O( y0 a/ l* G
print(G1.adj[1][2]) # 返回指定边的属性
$ t* j- L+ q+ f4 f" Z# {'weight': 3.6}
. G M0 q) Y" I. d: A: Y* W6 uprint(G1.degree(10)) # 返回指定顶点的度" l3 L* e, T+ d3 D( L6 C
# 2
% N1 `& W! ?7 q& F# ]; q
8 a6 b6 P2 }7 b- Y' uprint('nx.info:',nx.info(G1)) # 返回图的基本信息0 k6 s$ _# g* B) u" Q
print('nx.degree:',nx.degree(G1)) # 返回图中各顶点的度( p8 M5 H! ^1 a+ s% n
print('nx.density:',nx.degree_histogram(G1)) # 返回图中度的分布
0 L9 i8 C* X, }- S8 b; zprint('nx.pagerank:',nx.pagerank(G1)) # 返回图中各顶点的频率分布
+ E1 U! j5 Q6 e4 l# m; ^- @* p9 {3 e& D9 a8 y0 g% t
: ?2 R9 D1 H$ J+ f( k; f* d; g
" e" t8 e4 k9 y: C* u! T% I9 K1 |) L% B* d& m
2.3 图的属性和方法图的方法
6 e- U% M3 H# k& F& F: r! x/ E
8 H3 E0 L. b X: y. c" F) V& r方法 说明
$ E; m1 S* h6 O4 kG.has_node(n) 当图 G 中包括顶点 n 时返回 True
% m2 \( {) B( o% U: B7 jG.has_edge(u, v) 当图 G 中包括边 (u,v) 时返回 True" L* }: r" c8 i5 X- A& w
G.number_of_nodes() 返回 图 G 中的顶点的数量
/ O0 b) f" O* Y8 p' uG.number_of_edges() 返回 图 G 中的边的数量
6 S% d$ D# e: c( ZG.number_of_selfloops() 返回 图 G 中的自循环边的数量8 T. Y$ e+ a F* C3 B$ z2 h0 T
G.degree([nbunch, weight]) 返回 图 G 中的全部顶点或指定顶点的度0 v" x4 g! C! d, k
G.selfloop_edges([data, default]) 返回 图 G 中的全部的自循环边
' H! V' G( N' V3 _' oG.subgraph([nodes]) 从图 G1中抽取顶点[nodes]及对应边构成的子图7 H) U5 R. X$ c9 K
union(G1,G2) 合并图 G1、G2$ S3 g: X/ R" H# O, G) b1 H
nx.info(G) 返回图的基本信息0 m5 t7 b( @3 n7 _/ T7 P9 J1 w3 K1 q7 D
nx.degree(G) 返回图中各顶点的度
5 {" o' t+ @' X4 c& B# Z9 Snx.degree_histogram(G) 返回图中度的分布: A1 _0 X, K0 `; a# q, }0 r
nx.pagerank(G) 返回图中各顶点的频率分布- E& f; x' f- P, s5 _. ^; T
nx.add_star(G,[nodes],**attr) 向图 G 添加星形网络" j; K I; p, u! w/ U( x
nx.add_path(G,[nodes],**attr) 向图 G 添加一条路径
7 r/ I' ^& ^+ znx.add_cycle(G,[nodes],**attr) 向图 G 添加闭合路径
' {3 H% u# N2 H- u
/ S1 s! M; k. c! a! L" C* m2 {
9 d3 R% y" p5 l& U" ]例程:
& e: S* } E2 j; a8 cG1.clear() # 清空图G1
5 L3 o G) z# M$ N% x7 [nx.add_star(G1, [1, 2, 3, 4, 5], weight=1) # 添加星形网络:以第一个顶点为中心/ E( p+ f O5 U; I; \; q
# [(1, 2), (1, 3), (1, 4), (1, 5)]
7 w5 R. ]" a5 ]+ g4 knx.add_path(G1, [5, 6, 8, 9, 10], weight=2) # 添加路径:顺序连接 n个节点的 n-1条边
3 E; W* v6 g8 j o8 ]1 ~+ }. Y# [(5, 6), (6, 8), (8, 9), (9, 10)]/ K9 A; |& ?, c/ G: P+ W! G
nx.add_cycle(G1, [7, 8, 9, 10, 12], weight=3) # 添加闭合回路:循环连接 n个节点的 n 条边+ t. ^1 J/ ]; I0 q7 K+ ~2 O3 ^
# [(7, 8), (7, 12), (8, 9), (9, 10), (10, 12)] v' T) }! U: u. }7 ^
print(G1.nodes) # 返回所有的顶点 [node1,...]
2 a- g! I, l. M# `' ] ~# y' `nx.draw_networkx(G1)0 y6 w& _4 g5 w1 n# K& |) H0 {) M
plt.show()
* _/ M! U. O" I5 G2 s
( ?# N: Y, n. A! J) \G2 = G1.subgraph([1, 2, 3, 8, 9, 10])
- [& x6 ^' w8 V9 f r- BG3 = G1.subgraph([4, 5, 6, 7])
' O$ {: o9 \4 h0 u, J0 g3 ?) lG = nx.union(G2, G3)
% Q1 K4 d! r6 |% J0 cprint(G.nodes) # 返回所有的顶点 [node1,...]2 S# \% S$ n* k: z7 F% p1 {. u, f
# [1, 2, 3, 8, 9, 10, 4, 5, 6, 7]
6 h5 y, k J1 y, D4 K& I7 @8 D1 Q0 t' l" M
$ l! @3 C* V7 h0 k2 R2 G- P2 u3、图的绘制与分析3.1 图的绘制
$ J6 G- X. w% E可视化是图论和网络问题中很重要的内容。NetworkX 在 Matplotlib、Graphviz 等图形工具包的基础上,提供了丰富的绘图功能。" |9 O/ k- e( b u4 V" p' K: G
+ ~9 ~& W7 U2 g; _% G5 `; z. g# _
本系列拟对图和网络的可视化作一个专题,在此只简单介绍基于 Matplotlib 的基本绘图函数。基本绘图函数使用字典提供的位置将节点放置在散点图上,或者使用布局函数计算位置。
# E+ a6 x! v& n G6 L; ^3 d, ~+ A# q; |
方法 说明
( V8 ?0 v; N: ]0 o0 P, Y* `8 Jdraw(G[,pos,ax]) 基于 Matplotlib 绘制 图 G
* Z4 C3 [4 I: Rdraw_networkx(G[, pos, arrows, with_labels]) 基于 Matplotlib 绘制 图 G
) t1 R' Y) w2 N# f5 S& Mdraw_networkx_nodes(G, pos[, nodelist, . . . ]) 绘制图 G 的顶点
" P) z, {/ n2 R, A6 Idraw_networkx_edges(G, pos[, edgelist, . . . ]) 绘制图 G 的边& S7 U: w n- A* V1 _4 B+ z
draw_networkx_labels(G, pos[, labels, . . . ]) 绘制顶点的标签7 B: Y. K) U$ h# _! U
draw_networkx_edge_labels(G, pos[, . . . ]) 绘制边的标签# t& ~' z8 P! J* W3 ^
: s8 I# @! W* b) n0 M! g
7 g' ~! t5 G% w; n4 |% P5 M; |
其中,nx.draw() 和 nx.draw_networkx() 是最基本的绘图函数,并可以通过自定义函数属性或其它绘图函数设置不同的绘图要求。
7 a9 [) C7 b" e' vdraw(G, pos=None, ax=None, **kwds) draw_networkx(G, pos=None, arrows=True, with_labels=True, **kwds)
, k v! F2 ?( s# Z" n2 @* U常用的属性定义如下:
5 [6 l) c) u; k7 R& h
9 @( ~) R8 L# E. `7 I‘node_size’:指定节点的尺寸大小,默认3008 K, U( i3 W/ L, C
‘node_color’:指定节点的颜色,默认红色
- A: l. e# P/ h/ j) W$ y$ O‘node_shape’:节点的形状,默认圆形
+ Z: Q% Q+ f) W: E6 |8 Y( J: N( I'‘alpha’:透明度,默认1.0,不透明2 k4 z+ K h+ z0 t* P
‘width’:边的宽度,默认1.0$ `7 `. ~0 a1 A6 ]+ J
‘edge_color’:边的颜色,默认黑色" U) H* |# C+ W/ h$ Z
‘style’:边的样式,可选 ‘solid’、‘dashed’、‘dotted’、‘dashdot’
1 B( ?; I, G2 h) k‘with_labels’:节点是否带标签,默认True3 ^5 V8 @0 D% B. M0 m; `- K
‘font_size’:节点标签字体大小,默认12
' w3 P& G6 ]4 z& N3 |" R‘font_color’:节点标签字体颜色,默认黑色
' I! i* y- O t& a- Z/ i
% T0 F, b+ q6 s5 K5 x: e7 ~7 E8 l) w - F0 X' P+ S2 W2 {) m' s
3.2 图的分析NetwotkX 提供了图论函数对图的结构进行分析" }& U9 M7 A2 O8 {* K0 ?# B1 K
子图, y" T6 w, k% ^3 G( y, [
- 子图是指顶点和边都分别是图 G 的顶点的子集和边的子集的图。
- subgraph()方法,按顶点从图 G 中抽出子图。例程如前。
) H6 j) g2 t8 ]) q0 O+ ?: F 连通子图
( V! u+ J$ @" {) Y) C! ?. T0 d
' `# B8 c3 |1 M: h8 c, }- 如果图 G 中的任意两点间相互连通,则 G 是连通图。
- [color=rgba(0, 0, 0, 0.749019607843137)]connected_components()方法,返回连通子图的集合。
# p9 F6 Y# r% e3 A[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}]
# r8 e5 @- G# e3 }
6 c* ?& z& s. z; A+ e2 ?: {4 ]. o% U; L: k
& F$ x% Q/ T- b) Z" M
5 m4 @) {1 f% l# a/ P" i. Z |