Python小白的数学建模课-图论的基本概念6 q* V) i. E6 k+ K5 z
( P1 K, W4 ] B
- 图论中所说的图,不是图形图像或地图,而是指由顶点和边所构成的图形结构。
- 图论不仅与拓扑学、计算机数据结构和算法密切相关,而且正在成为机器学习的关键技术。
- 本系列结合数学建模的应用需求,来介绍 NetworkX 图论与复杂网络工具包的基本功能和典型算法。0 D' M2 t$ A! j3 j3 j0 C: @9 @1 I: a
4 ]! b( Q+ S8 T& U
1. 图论1.1 图论是什么6 y+ `( {* a$ ~* a9 a6 w
图论〔Graph Theory〕以图为研究对象,是离散数学的重要内容。图论不仅与拓扑学、计算机数据结构和算法密切相关,而且正在成为机器学习的关键技术。7 y& R, V' G. Y' H; Q: W# ~
0 y! f+ K# E' L, f# g/ k1 Q图论中所说的图,不是指图形图像(image)或地图(map),而是指由顶点(vertex)和连接顶点的边(edge)所构成的关系结构。6 z" n* i0 P' t
/ G8 y: H( R3 C9 ]
图提供了一种处理关系和交互等抽象概念的更好的方法,它还提供了直观的视觉方式来思考这些概念。
* D, G7 x- w, f* E: o2 o
* T# O8 Z( U- F- U F- C) D1.2 NetworkX 工具包
6 Z, ?- Y( N9 PNetworkX 是基于 Python 语言的图论与复杂网络工具包,用于创建、操作和研究复杂网络的结构、动力学和功能。7 R8 h2 K5 T m* d' w
O' s6 o& K& X: rNetworkX 可以以标准和非标准的数据格式描述图与网络,生成图与网络,分析网络结构,构建网络模型,设计网络算法,绘制网络图形。* z; J( P2 v2 z2 d
' A- r5 n! t. ^4 I7 u* \NetworkX 提供了图形的类、对象、图形生成器、网络生成器、绘图工具,内置了常用的图论和网络分析算法,可以进行图和网络的建模、分析和仿真。2 A- z) y. q. G e2 A Q* S
; b; r% b! }# w3 `" ENetworkX 的功能非常强大和庞杂,所涉及内容远远、远远地超出了数学建模的范围,甚至于很难进行系统的概括。本系列结合数学建模的应用需求,来介绍 NetworkX 图论与复杂网络工具包的基本功能和典型算法。
7 P8 k* A8 D! n6 ?) K. l; C0 e3 @: I" J$ `
% h# z7 l5 ^3 Q2 g + ~4 T+ Q Z( p, {0 X4 t, c1 T/ N
2、图、顶点和边的创建与基本操作& [* z: R2 c( x- y" w( T% U
图由顶点和连接顶点的边构成,但与顶点的位置、边的曲直长短无关。 Networkx 支持创建简单无向图、有向图和多重图;内置许多标准的图论算法,节点可为任意数据;支持任意的边值维度,功能丰富,简单易用。 2.1 图的基本概念
' v& A+ @" z/ N# ^- z3 K6 C图(Graph):图是由若干顶点和连接顶点的边所构成关系结构。3 j6 n# ], R9 h" ^
顶点(Node):图中的点称为顶点,也称节点。
) s S7 D1 T% j/ d边(Edge):顶点之间的连线,称为边。7 Q* }4 Y; ~0 |! X) y
平行边(Parallel edge):起点相同、终点也相同的两条边称为平行边。. _* X; x O- d9 j- ? z
循环(Cycle):起点和终点重合的边称为循环。
# c2 q$ u g+ X/ Q6 O1 @) T6 }) t有向图(Digraph):图中的每条边都带有方向,称为有向图。
+ h! D6 F9 S- M1 D无向图(Undirected graph):图中的每条边都没有方向,称为无向图。
) ^! }7 ^" \$ F8 Q赋权图(Weighted graph):图中的每条边都有一个或多个对应的参数,称为赋权图。该参数称为这条边的权,权可以用来表示两点间的距离、时间、费用。+ s; h5 p9 `1 D) d A+ F
度(Degree):与顶点相连的边的数量,称为该顶点的度。" K" Z) D, X% v1 t+ e' n
; ]& U; h, \8 z& K& f: l7 i- I
2.2 图、顶点和边的操作) G( l/ a. Q$ o; a" @
Networkx很容易创建图、向图中添加顶点和边、从图中删除顶点和边,也可以查看、删除顶点和边的属性。* ?8 J& j+ { z; Z7 W: T
+ @. ~' U9 {" u/ X1 ]
2.2.1 图的创建Graph() 类、DiGraph() 类、MultiGraph() 类和 MultiDiGraph() 类分别用来创建:无向图、有向图、多图和有向多图。定义和例程如下:
% s5 S, }& Y+ q" o3 d
. N9 R/ H2 t% o) o& Kclass Graph(incoming_graph_data=None, **attr)
# O& J8 m6 D6 Z4 D* j# Kimport networkx as nx # 导入 NetworkX 工具包6 X( @9 |8 `3 {
3 ]- I r' M* C9 L' `* m7 @9 S
# 创建 图& C2 t$ V% A; T C
G1 = nx.Graph() # 创建:空的 无向图
3 A6 H; H9 p2 @, K9 N% v5 {G2 = nx.DiGraph() #创建:空的 有向图
; j4 @' f$ G- e3 H8 w7 k/ i- L0 ZG3 = nx.MultiGraph() #创建:空的 多图
& a, g4 @+ p, ~0 e8 n |G4 = nx.MultiDiGraph() #创建:空的 有向多图0 o; M9 |8 {% I( V
% @+ }/ Q9 |$ `& M8 ?7 O8 K3 K6 s; O, P
2.2.2 顶点的添加、删除和查看& h# O: Q' E) R7 M/ Y* t
图的每个顶点都有唯一的标签属性(label),可以用整数或字符类型表示,顶点还可以自定义任意属性。 顶点的常用操作:添加顶点,删除顶点,定义顶点属性,查看顶点和顶点属性。定义和例程如下:
7 _0 ^: Z: P. g# ?: U |Graph.add_node(node_for_adding, **attr)3 z: x4 J* P% p7 R- t8 f, X
Graph.add_nodes_from(nodes_for_adding, **attr)' }6 d j+ h; Z
Graph.remove_node(n)
1 Y; Y/ c0 h5 o4 jGraph.remove_nodes_from(nodes)
$ I; I1 A# g0 [0 @3 Z& E$ H6 n1 Z
* n2 N. L3 a: ~- T" G, j% q7 A# 顶点(node)的操作
( ^+ t& `# H2 w( I! _* E. ?& _# 向图中添加顶点
3 e O8 l. O) G! qG1.add_node(1) # 向 G1 添加顶点 1
. ~, F: c* r" @8 s; B. \G1.add_node(1, name='n1', weight=1.0) # 添加顶点 1,定义 name, weight 属性
P! ^/ h, P, S* A. S9 x) ^6 Z( c3 i6 G8 VG1.add_node(2, date='May-16') # 添加顶点 2,定义 time 属性
, i. h. ^: ]$ y1 T0 A4 AG1.add_nodes_from([3, 0, 6], dist=1) # 添加多个顶点,并定义属性
; t: Q/ w* ], D8 X7 Z i1 TG1.add_nodes_from(range(10, 15)) # 向图 G1 添加顶点 10~14
; w8 M4 h V5 |4 y* N6 _6 _6 g3 b4 d8 n/ k" K( n
# 查看顶点和顶点属性
7 O4 f* l0 l* U7 I- kprint(G1.nodes()) # 查看顶点列表* ~, I! T, A9 U6 x# ^
# [1, 2, 3, 0, 6, 10, 11, 12, 13, 14]
) ?! }/ [: I& P9 U; M! Fprint(G1._node) # 查看顶点属性
8 @5 k4 A+ c+ H; C3 q7 k8 P5 T# {1: {'name': 'n1', 'weight': 1.0}, 2: {'date': 'May-16'}, 3: {'dist': 1}, 0: {'dist': 1}, 6: {'dist': 1}, 10: {}, 11: {}, 12: {}, 13: {}, 14: {}}
! F8 l) a) h. N# D* O4 }5 ~
( v) b9 B9 D; |) s# z+ D/ H+ ?# 从图中删除顶点
' J1 t% G" B$ @' H- ^: QG1.remove_node(1) # 删除顶点 E4 l5 w8 Y6 b) N4 x
G1.remove_nodes_from([1, 11, 13, 14]) # 通过顶点标签的 list 删除多个顶点
% Q1 C: W# f# z/ g( I @print(G1.nodes()) # 查看顶点
: T$ k& p3 ~4 M2 c# [2, 3, 0, 6, 10, 12] # 顶点列表
0 G2 w" p0 T* t8 ~2 @5 K _2.2.3 边的添加、删除和查看边是两个顶点之间的连接,在 NetworkX 中 边是由对应顶点的名字的元组组成 e=(node1,node2)。边可以设置权重、关系等属性。 边的常用操作:添加边,删除边,定义边的属性,查看边和边的属性。向图中添加边时,如果边的顶点是图中不存在的,则自动向图中添加该顶点。 Graph.add_edge(u_of_edge, v_of_edge, **attr)2 L% q' _5 p- T: c
Graph.add_edges_from(ebunch_to_add, **attr)
7 K. l* U5 i+ c. |! Y. LGraph.add_weighted_edges_from(ebunch_to_add, weight=‘weight’, **attr)9 |4 b9 r& N# Y T2 Z; A7 \
, F$ z* b9 G: \: P) V# 边(edge)的操作
% ~3 |+ B& m1 U n, k& c1 t# 向图中添加边
, A7 Q) u+ `3 N- B$ ]G1.add_edge(1,5) # 向 G1 添加边,并自动添加图中没有的顶点5 x: `, X7 _- e4 v9 Q! ]
G1.add_edge(0,10, weight=2.7) # 向 G1 添加边,并设置边的属性
9 \) }+ L9 \# h% ?G1.add_edges_from([(1,2,{'weight':0}), (2,3,{'color':'blue'})]) # 向图中添加边,并设置属性
6 J5 W, a2 }1 R7 x7 w! K+ t1 B- {' WG1.add_edges_from([(3,6),(1,2),(6,7),(5,10),(0,1)]) # 向图中添加多条边: ^7 { l" \( ?0 w
G1.add_weighted_edges_from([(1,2,3.6),[6,12,0.5]]) # 向图中添加多条赋权边: (node1,node2,weight)1 G/ j: B& d# @) C' @
print(G1.nodes()) # 查看顶点2 \* P% i* S" |
# [2, 3, 0, 6, 10, 12, 1, 5, 7] # 自动添加了图中没有的顶点
- U, @% W* { `, ]- V& c7 |' X7 y
m( P8 P5 b8 L2 I# 从图中删除边
1 R0 \2 D) N t* l3 Q; TG1.remove_edge(0,1) # 从图中删除边 0-1. W/ `6 ?6 @1 t9 o0 f/ B
G1.remove_edges_from([(2,3),(1,5),(6,7)]) # 从图中删除多条边
9 n6 d8 |3 x7 w; s
( k k: ?8 F: y* m6 k8 {+ N# 查看 边和边的属性
+ _/ N: [: H+ d0 C! Tprint(G1.edges) # 查看所有的边
2 v) z' B6 e& M! Z% J- ?: ?7 x* J[(2, 1), (3, 6), (0, 10), (6, 12), (10, 5)]
, i! O. x+ m! w4 @0 Uprint(G1.get_edge_data(1,2)) # 查看指定边的属性2 Z% {! h# U4 F* Y3 b2 d6 c
# {'weight': 3.6}
. @* E# H6 \- j8 E7 Aprint(G1[1][2]) # 查看指定边的属性
h2 Y/ L: D3 w% w. f& o: Q. g! M3 Y# {'weight': 3.6}4 e/ E- m; h' \9 J: ], q6 U/ n
print(G1.edges(data=True)) # 查看所有边的属性
: Y1 i s3 u. _+ G8 j+ p5 I# [(2, 1, {'weight': 3.6}), (3, 6, {}), (0, 10, {'weight': 2.7}), (6, 12, {'weight': 0.5}), (10, 5, {})]
, s# i [, l3 Q, E% F7 b4 o/ ~9 } C& X1 @
2.2.4 查看图、顶点和边的信息& X" t* P- h; M. A4 b' e7 Q0 o
' U1 T9 h- e1 d* ], ]# 查看图、顶点和边的信息
: p- ~# v: c" M; Tprint(G1.nodes) # 返回所有的顶点 [node1,...]& c# [. g9 V& S4 e$ c& t
# [2, 3, 0, 6, 10, 12, 1, 5, 7]
: M" b: `' R4 q) C6 `print(G1.edges) # 返回所有的边 [(node1,node2),...]( _& W" @! X: z; Q; }
# [(2, 1), (3, 6), (0, 10), (6, 12), (10, 5)]
: g4 d. ~/ [7 {7 Z+ S( s/ b, m6 Y! Nprint(G1.degree) # 返回各顶点的度 [(node1,degree1),...]4 K) _% j9 |' n- \
# [(2, 1), (3, 1), (0, 1), (6, 2), (10, 2), (12, 1), (1, 1), (5, 1), (7, 0)]
m8 o& C( @) S3 O% L! uprint(G1.number_of_nodes()) # 返回顶点的数量/ w8 b* ?. K) m; s
# 9, Y$ K5 s$ p- t& E' ?
print(G1.number_of_edges()) # 返回边的数量
2 j3 [- z7 ?! {0 [1 g# 51 B$ @/ e1 T7 m9 V8 Y
print(G1[10]) # 返回与指定顶点相邻的所有顶点的属性
/ B6 p; R( p& a, o- G# \6 ~# {0: {'weight': 2.7}, 5: {}}9 i% {% l* X% H( R& {
print(G1.adj[10]) # 返回与指定顶点相邻的所有顶点的属性& ?. Z2 p6 w6 P* C; P0 B V5 Z
# {0: {'weight': 2.7}, 5: {}}; U7 V) `& p# L0 C1 q' c$ B/ c
print(G1[1][2]) # 返回指定边的属性% Q1 K* q7 i- P: P$ I9 e2 b
# {'weight': 3.6}: U6 {) Y- I% z! l. I1 r2 \
print(G1.adj[1][2]) # 返回指定边的属性
7 s, w# Y# l/ \/ [2 s$ x# {'weight': 3.6}# t9 R. Z, _& E+ J2 Z% Y. C
print(G1.degree(10)) # 返回指定顶点的度; }" F6 u) j% q- k' M
# 2' ` {# S+ C' S3 c. q7 y( I
+ [8 I$ f# k8 Q
print('nx.info:',nx.info(G1)) # 返回图的基本信息1 q- Z' N' l* {$ r7 r) @ @5 j6 @
print('nx.degree:',nx.degree(G1)) # 返回图中各顶点的度1 T( r, Z+ B( l6 ?
print('nx.density:',nx.degree_histogram(G1)) # 返回图中度的分布" ]: \, Z# {) H* E$ H* F7 t) g
print('nx.pagerank:',nx.pagerank(G1)) # 返回图中各顶点的频率分布5 A! L8 h& A4 c/ Y. {
3 P* m5 D% X6 e9 x; ?* b
. {* V# U g* u! @" M+ c# t( ~0 f9 H& }! [
4 ]: l; W6 a A# L
9 m$ }8 D/ r2 ]2.3 图的属性和方法图的方法* N/ r$ X: Q. `8 | g* I5 S
" i6 z* u4 `7 A
方法 说明/ ]; D0 A; i- N! g- W! V( [# B3 O
G.has_node(n) 当图 G 中包括顶点 n 时返回 True. ^7 E6 c$ B; J
G.has_edge(u, v) 当图 G 中包括边 (u,v) 时返回 True
$ n9 a- e& N' f& {G.number_of_nodes() 返回 图 G 中的顶点的数量
8 H$ }# ?1 m/ N, r9 n8 X$ U: MG.number_of_edges() 返回 图 G 中的边的数量/ k8 z" a! v& u$ ~; y' H, D
G.number_of_selfloops() 返回 图 G 中的自循环边的数量+ g; V# o' R) M N) |# ^4 S/ u( @
G.degree([nbunch, weight]) 返回 图 G 中的全部顶点或指定顶点的度5 C; A: ^" h# k. B
G.selfloop_edges([data, default]) 返回 图 G 中的全部的自循环边
7 s( U) H& K: j4 u$ wG.subgraph([nodes]) 从图 G1中抽取顶点[nodes]及对应边构成的子图
' J* a6 V m- ^. iunion(G1,G2) 合并图 G1、G2
4 s4 z: M7 s- I* |nx.info(G) 返回图的基本信息! N. F8 H9 c9 \4 u% z/ s+ J
nx.degree(G) 返回图中各顶点的度 a! l' o+ M9 M0 }7 I
nx.degree_histogram(G) 返回图中度的分布0 j8 ]+ H q# }3 P K
nx.pagerank(G) 返回图中各顶点的频率分布
1 g: q0 A8 B7 u; [% N# nnx.add_star(G,[nodes],**attr) 向图 G 添加星形网络
4 }) W0 a0 L- C6 n8 C5 i6 rnx.add_path(G,[nodes],**attr) 向图 G 添加一条路径7 E& ?- Z% F$ J1 c& S6 X
nx.add_cycle(G,[nodes],**attr) 向图 G 添加闭合路径
* w: a% H! u# Q5 D; G6 s+ Z, N- r' N
- u8 p" V2 d3 [% }' @0 ~" d例程:
: a# g" q5 B! e1 t) eG1.clear() # 清空图G1$ o8 Q$ ?7 Q6 |1 L6 F8 V0 h4 X
nx.add_star(G1, [1, 2, 3, 4, 5], weight=1) # 添加星形网络:以第一个顶点为中心
2 ~# d5 e" U( z9 {# K, H- J6 e# [(1, 2), (1, 3), (1, 4), (1, 5)]" e2 v, k( t! G1 O2 W& T
nx.add_path(G1, [5, 6, 8, 9, 10], weight=2) # 添加路径:顺序连接 n个节点的 n-1条边* S G- t5 Z7 w) l( {$ i+ V
# [(5, 6), (6, 8), (8, 9), (9, 10)]) U. |- ] M0 |) \& J" n4 E
nx.add_cycle(G1, [7, 8, 9, 10, 12], weight=3) # 添加闭合回路:循环连接 n个节点的 n 条边
3 M, `" g5 ^7 R8 a, b& z# [(7, 8), (7, 12), (8, 9), (9, 10), (10, 12)]6 O$ ?% `; t. K9 t2 A/ k
print(G1.nodes) # 返回所有的顶点 [node1,...]
6 X, Q/ d6 e7 S: n; vnx.draw_networkx(G1)- j* S. L s5 k0 J- n' e
plt.show()5 a* p" v! ]+ _
1 x5 H& b, x& |: d# j& ~G2 = G1.subgraph([1, 2, 3, 8, 9, 10])
2 s& ?' I+ t" @9 z1 LG3 = G1.subgraph([4, 5, 6, 7]) s/ L/ C. f2 X0 C% M6 u' M
G = nx.union(G2, G3)
6 S# l& h$ W7 w1 m, r# C6 Q, O) q tprint(G.nodes) # 返回所有的顶点 [node1,...]
! {, U+ u+ O6 @3 c; H# [1, 2, 3, 8, 9, 10, 4, 5, 6, 7]0 ?; b8 F/ U1 L
. a% {3 R, W+ W, ]5 K7 g
* n }" C4 H s/ X2 t2 a3、图的绘制与分析3.1 图的绘制5 s# \. o s% s8 `" |8 V' n
可视化是图论和网络问题中很重要的内容。NetworkX 在 Matplotlib、Graphviz 等图形工具包的基础上,提供了丰富的绘图功能。
& Z. q- n* r4 y+ H1 W6 k- [; ^ p3 T+ Q/ r: T* j
本系列拟对图和网络的可视化作一个专题,在此只简单介绍基于 Matplotlib 的基本绘图函数。基本绘图函数使用字典提供的位置将节点放置在散点图上,或者使用布局函数计算位置。5 q0 R: ^9 Q. Q2 M, O# W" z
! e( T" r" q8 h! }1 D% b0 C
方法 说明
: t. a: p& {! s4 I# Y0 n! ^/ S' kdraw(G[,pos,ax]) 基于 Matplotlib 绘制 图 G
# u2 Z- H# e! y( n4 y4 W7 bdraw_networkx(G[, pos, arrows, with_labels]) 基于 Matplotlib 绘制 图 G
- r" w+ x* g3 v# Mdraw_networkx_nodes(G, pos[, nodelist, . . . ]) 绘制图 G 的顶点 O1 k) q6 k7 L# {: b# k
draw_networkx_edges(G, pos[, edgelist, . . . ]) 绘制图 G 的边
2 p, C8 p, I0 o# j5 s, N; S) ]" Edraw_networkx_labels(G, pos[, labels, . . . ]) 绘制顶点的标签
, `; P8 `& P. X1 |. O( v, E6 bdraw_networkx_edge_labels(G, pos[, . . . ]) 绘制边的标签
) X6 a& [6 f, I; G6 ?: y# }/ I# ^' s4 L4 P2 Q( q; s: u; \! T
& F" q* P: I' o2 [& L3 L0 g其中,nx.draw() 和 nx.draw_networkx() 是最基本的绘图函数,并可以通过自定义函数属性或其它绘图函数设置不同的绘图要求。
' g" V6 r9 s0 c: a* R+ C/ Kdraw(G, pos=None, ax=None, **kwds) draw_networkx(G, pos=None, arrows=True, with_labels=True, **kwds)
# ]) D$ a! T3 W- u) k# S2 ]8 K. x" J常用的属性定义如下:
" \" ~& t7 Y8 o1 r6 l" C* k
4 j2 ]" m1 \) p0 a‘node_size’:指定节点的尺寸大小,默认3005 ]. P; i h' k* R" k1 T
‘node_color’:指定节点的颜色,默认红色
: o, Y- p+ U1 r+ t- e! V‘node_shape’:节点的形状,默认圆形
+ B8 O* G: b* U2 T& a'‘alpha’:透明度,默认1.0,不透明
. c2 T9 b; D6 x6 T2 t# j‘width’:边的宽度,默认1.0
; ?; T8 O3 ^7 ]7 M‘edge_color’:边的颜色,默认黑色5 A& X: u; p$ E6 {9 A; c" J
‘style’:边的样式,可选 ‘solid’、‘dashed’、‘dotted’、‘dashdot’
. _( `# B$ K" @% a‘with_labels’:节点是否带标签,默认True
) B3 \3 b3 }% k‘font_size’:节点标签字体大小,默认122 o+ c, Y* \0 f8 V0 L
‘font_color’:节点标签字体颜色,默认黑色* }* i! h: P4 `7 |% N! u- }
) I* n- B+ f( f4 w; X! L
![]()
* l2 W7 d7 z# z6 A. v3.2 图的分析NetwotkX 提供了图论函数对图的结构进行分析* v& ^9 g* q( d" |- t+ q8 F* y* R
子图
; H7 r+ w- b j6 q7 |$ v- 子图是指顶点和边都分别是图 G 的顶点的子集和边的子集的图。
- subgraph()方法,按顶点从图 G 中抽出子图。例程如前。; a% ]1 x% S {/ b
连通子图+ l' s7 f5 q+ E* k# F
4 H/ ~+ }$ c% ~3 z9 E* K0 g- o- 如果图 G 中的任意两点间相互连通,则 G 是连通图。
- [color=rgba(0, 0, 0, 0.749019607843137)]connected_components()方法,返回连通子图的集合。2 ~' M- N4 |+ M- i
[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}]
# u, D5 G4 f0 A& o 2 H9 x1 S! ~$ J2 @ a
) I6 c+ o E3 X5 w' M. O' h; M1 v4 t( T0 _; a, Y* B
; S @+ [3 w( q' l5 \9 H2 ~+ k |