Python小白的数学建模课-图论的基本概念5 Q$ W+ P. z. @# @/ k( D) _- o& r
% V+ }* G, y2 @, v) X. H- 图论中所说的图,不是图形图像或地图,而是指由顶点和边所构成的图形结构。
- 图论不仅与拓扑学、计算机数据结构和算法密切相关,而且正在成为机器学习的关键技术。
- 本系列结合数学建模的应用需求,来介绍 NetworkX 图论与复杂网络工具包的基本功能和典型算法。! o, B0 Q* ?- x3 i, D* D, W, d
3 `) w! Z; ~4 Q' Q. T$ Q
1. 图论1.1 图论是什么
# c8 A3 ~, V6 N: z图论〔Graph Theory〕以图为研究对象,是离散数学的重要内容。图论不仅与拓扑学、计算机数据结构和算法密切相关,而且正在成为机器学习的关键技术。
* n3 a4 r8 }( _ _. I) }& `, K2 Z; ^: k+ R2 Z' A
图论中所说的图,不是指图形图像(image)或地图(map),而是指由顶点(vertex)和连接顶点的边(edge)所构成的关系结构。
, e$ B. _' P% i% d/ Z! d# R( O2 Z: e* Y0 [; N; x' j
图提供了一种处理关系和交互等抽象概念的更好的方法,它还提供了直观的视觉方式来思考这些概念。
! \% [1 l* }8 S4 e, q
7 W7 P+ c4 }7 N& l9 @) X3 l' M1.2 NetworkX 工具包! Y8 `! v" w1 A; i. |
NetworkX 是基于 Python 语言的图论与复杂网络工具包,用于创建、操作和研究复杂网络的结构、动力学和功能。
) [' Z; O7 E% D- k
( o% [ C: V4 X* g2 cNetworkX 可以以标准和非标准的数据格式描述图与网络,生成图与网络,分析网络结构,构建网络模型,设计网络算法,绘制网络图形。0 t0 a0 G+ u$ e
% x* t9 y) J( {5 k L
NetworkX 提供了图形的类、对象、图形生成器、网络生成器、绘图工具,内置了常用的图论和网络分析算法,可以进行图和网络的建模、分析和仿真。. @( ]" G! Z: {; d5 k
/ V5 @4 i7 E9 X* h; JNetworkX 的功能非常强大和庞杂,所涉及内容远远、远远地超出了数学建模的范围,甚至于很难进行系统的概括。本系列结合数学建模的应用需求,来介绍 NetworkX 图论与复杂网络工具包的基本功能和典型算法。
/ i* w" M/ C! w Y- \/ t2 A7 r/ J" Q4 N
% W. B/ u7 e4 d ?; s$ R2 q2 \5 G7 _
2、图、顶点和边的创建与基本操作, s" E1 O+ y/ f; m
图由顶点和连接顶点的边构成,但与顶点的位置、边的曲直长短无关。 Networkx 支持创建简单无向图、有向图和多重图;内置许多标准的图论算法,节点可为任意数据;支持任意的边值维度,功能丰富,简单易用。 2.1 图的基本概念 O3 R' A$ I' x
图(Graph):图是由若干顶点和连接顶点的边所构成关系结构。! U/ x! `! {* A" u
顶点(Node):图中的点称为顶点,也称节点。2 g) b, f& {$ |; \* w. U
边(Edge):顶点之间的连线,称为边。8 N0 _! e6 Z; }$ L9 X X! b
平行边(Parallel edge):起点相同、终点也相同的两条边称为平行边。, l' W% s; i5 r4 Y
循环(Cycle):起点和终点重合的边称为循环。. | p6 \( M# [' d$ H1 g4 o
有向图(Digraph):图中的每条边都带有方向,称为有向图。* Z% _& W8 @, V9 q
无向图(Undirected graph):图中的每条边都没有方向,称为无向图。8 H. u; r/ J- r# Q' |% a
赋权图(Weighted graph):图中的每条边都有一个或多个对应的参数,称为赋权图。该参数称为这条边的权,权可以用来表示两点间的距离、时间、费用。
; g I& P, J l度(Degree):与顶点相连的边的数量,称为该顶点的度。
, o0 q0 W3 d W; z1 D
3 h) x7 J9 Z- w" x+ n' l2.2 图、顶点和边的操作
4 ]( Q) [+ m b- ^( [1 cNetworkx很容易创建图、向图中添加顶点和边、从图中删除顶点和边,也可以查看、删除顶点和边的属性。: o( _# S$ C% o
+ k. K: n( a) F
2.2.1 图的创建Graph() 类、DiGraph() 类、MultiGraph() 类和 MultiDiGraph() 类分别用来创建:无向图、有向图、多图和有向多图。定义和例程如下:# R7 q) X1 r" t% p8 j$ Q
' t# m! b* M" g+ \' ^) S4 `, M
class Graph(incoming_graph_data=None, **attr)) W4 H( @& w8 J/ x; V
import networkx as nx # 导入 NetworkX 工具包8 K* C l( H3 \8 M% u9 }: I/ g
) t0 ^+ C f. D) o% |! p, T' u
# 创建 图
. P5 o% z5 V- p7 uG1 = nx.Graph() # 创建:空的 无向图5 s- k2 i1 {5 w
G2 = nx.DiGraph() #创建:空的 有向图# x4 B* I: U; C) d/ o2 H9 B5 ~. W
G3 = nx.MultiGraph() #创建:空的 多图
8 [& i- j/ M" K! W% eG4 = nx.MultiDiGraph() #创建:空的 有向多图
8 I/ _+ H: r: E* \. O4 x6 R; e4 Y% S1 _4 F$ \
) C- q/ \' ?" F, Z5 x2 c: r% D" E2.2.2 顶点的添加、删除和查看2 \3 G/ }: U( z# `- E( B2 |0 d7 _! V
图的每个顶点都有唯一的标签属性(label),可以用整数或字符类型表示,顶点还可以自定义任意属性。 顶点的常用操作:添加顶点,删除顶点,定义顶点属性,查看顶点和顶点属性。定义和例程如下: 4 B2 k- n% o3 S8 t$ T
Graph.add_node(node_for_adding, **attr)
$ X! `1 B! h# j# P4 Q" n: hGraph.add_nodes_from(nodes_for_adding, **attr)$ T5 J- x: r9 L$ B) A* R
Graph.remove_node(n)' q5 b' x2 V" t( A
Graph.remove_nodes_from(nodes)7 j# l5 h0 ^2 q% O
7 ^/ O- F) i' s0 h# 顶点(node)的操作. t4 j5 `4 ]( ]- e; ]# O; P$ ~( B
# 向图中添加顶点
# \+ o! U7 A' `6 @+ jG1.add_node(1) # 向 G1 添加顶点 1
7 c$ ~ [9 ^9 x' p+ \ yG1.add_node(1, name='n1', weight=1.0) # 添加顶点 1,定义 name, weight 属性
+ t# q. |: I! ~3 s) n. Q: f! s; F/ P& KG1.add_node(2, date='May-16') # 添加顶点 2,定义 time 属性
+ A# U/ y/ v) {5 V% [+ _G1.add_nodes_from([3, 0, 6], dist=1) # 添加多个顶点,并定义属性0 p5 y# A/ M* n* M! ^1 T8 ^
G1.add_nodes_from(range(10, 15)) # 向图 G1 添加顶点 10~14: `/ L8 Z9 \- c$ S8 o8 y
8 [! n8 z) _' T/ f/ e
# 查看顶点和顶点属性
/ W7 Q, B9 T) k2 n4 x0 \print(G1.nodes()) # 查看顶点列表
% R6 R% l; i3 @6 C& h, e; B' w# [1, 2, 3, 0, 6, 10, 11, 12, 13, 14]3 t; n% l0 A4 Q& F% W, m
print(G1._node) # 查看顶点属性. g. ^; q6 V s; P
# {1: {'name': 'n1', 'weight': 1.0}, 2: {'date': 'May-16'}, 3: {'dist': 1}, 0: {'dist': 1}, 6: {'dist': 1}, 10: {}, 11: {}, 12: {}, 13: {}, 14: {}}
8 f& f. A4 a& A3 i2 ], \8 g) N- A' Z3 t+ f0 |
# 从图中删除顶点4 i: ~% C) o$ d* U
G1.remove_node(1) # 删除顶点
) N4 f" i, n% n' @+ L" ~+ |' R: g+ EG1.remove_nodes_from([1, 11, 13, 14]) # 通过顶点标签的 list 删除多个顶点% \5 U8 w. @( U' T
print(G1.nodes()) # 查看顶点5 L \0 D- o, |" T( O
# [2, 3, 0, 6, 10, 12] # 顶点列表, d3 ^ \& Y3 t9 c3 _4 m
2.2.3 边的添加、删除和查看边是两个顶点之间的连接,在 NetworkX 中 边是由对应顶点的名字的元组组成 e=(node1,node2)。边可以设置权重、关系等属性。 边的常用操作:添加边,删除边,定义边的属性,查看边和边的属性。向图中添加边时,如果边的顶点是图中不存在的,则自动向图中添加该顶点。 Graph.add_edge(u_of_edge, v_of_edge, **attr)
1 W" q# g3 W! Y9 H; L! j0 BGraph.add_edges_from(ebunch_to_add, **attr)! t* V# D: v# R/ P! j% ~
Graph.add_weighted_edges_from(ebunch_to_add, weight=‘weight’, **attr)
% C& ?, s9 |8 } \
. H! l0 z& s% |% i8 p- z0 P# 边(edge)的操作
# I1 e1 v3 P8 ^+ f# 向图中添加边
, H2 T/ C( L" [) U. k! QG1.add_edge(1,5) # 向 G1 添加边,并自动添加图中没有的顶点2 F, }) h; z' w- @6 ], L* y
G1.add_edge(0,10, weight=2.7) # 向 G1 添加边,并设置边的属性
' b3 m6 O u: f b6 S0 fG1.add_edges_from([(1,2,{'weight':0}), (2,3,{'color':'blue'})]) # 向图中添加边,并设置属性
6 J1 b# X- k% e( {! F6 w+ k1 }G1.add_edges_from([(3,6),(1,2),(6,7),(5,10),(0,1)]) # 向图中添加多条边& P u( l$ ~. Y2 J9 v2 h0 r9 E. p
G1.add_weighted_edges_from([(1,2,3.6),[6,12,0.5]]) # 向图中添加多条赋权边: (node1,node2,weight)
0 l. V! G* s+ S ^) m* G0 _; Cprint(G1.nodes()) # 查看顶点
! v e3 N4 L- F7 T- ` ~# [2, 3, 0, 6, 10, 12, 1, 5, 7] # 自动添加了图中没有的顶点
5 h) d5 `' I) Y4 \ n4 v' r6 c6 w- E+ l' X$ G. G! y
# 从图中删除边
" o/ Y% t' j2 w! z8 Q' a$ r6 vG1.remove_edge(0,1) # 从图中删除边 0-10 _) x L1 R$ L; [+ Y
G1.remove_edges_from([(2,3),(1,5),(6,7)]) # 从图中删除多条边
/ z' `) `# s D1 w1 e
9 I' T! W' n9 D: ~# 查看 边和边的属性. m' y n% e& Q
print(G1.edges) # 查看所有的边
7 A/ s1 L, O& k. o[(2, 1), (3, 6), (0, 10), (6, 12), (10, 5)]8 G7 q( ]6 j9 w# |% g' q
print(G1.get_edge_data(1,2)) # 查看指定边的属性; {* ~' B- x+ a7 J3 ]
# {'weight': 3.6}
5 K) t( {# H. W: s0 Bprint(G1[1][2]) # 查看指定边的属性4 W/ E) E+ J y' q' ]0 g
# {'weight': 3.6}
$ z7 _* {/ H2 @0 h& O; P3 Q) Uprint(G1.edges(data=True)) # 查看所有边的属性
* Y4 M- c& @" x8 Z2 u, H7 Z# [(2, 1, {'weight': 3.6}), (3, 6, {}), (0, 10, {'weight': 2.7}), (6, 12, {'weight': 0.5}), (10, 5, {})]
$ m" @* x6 L; k% O4 p# a
4 z( W# {1 j" N3 S0 h5 x4 f u5 x2.2.4 查看图、顶点和边的信息
& b- v1 }3 e7 b+ ^/ r' d+ i! K+ P8 X+ n0 r
# 查看图、顶点和边的信息2 H; O! L' B, ` U: K x
print(G1.nodes) # 返回所有的顶点 [node1,...]
! C! P! U* c. s2 F# [2, 3, 0, 6, 10, 12, 1, 5, 7]
; \4 G2 S6 j9 V2 I# @( h Zprint(G1.edges) # 返回所有的边 [(node1,node2),...]
' X; X+ m! ~5 F! A3 T8 m6 c# [(2, 1), (3, 6), (0, 10), (6, 12), (10, 5)]
) p: u3 }" `0 d ~3 ^print(G1.degree) # 返回各顶点的度 [(node1,degree1),...]: ?! {" ~, x! L6 k c5 p
# [(2, 1), (3, 1), (0, 1), (6, 2), (10, 2), (12, 1), (1, 1), (5, 1), (7, 0)]2 F3 x) e0 D, Z, U7 u& i
print(G1.number_of_nodes()) # 返回顶点的数量$ o& ^9 r* N+ c* f7 C2 W( V6 e# _9 L
# 9
: H7 z; d; M- s& A- c3 `print(G1.number_of_edges()) # 返回边的数量3 }! j5 Q# Q7 w0 \+ n: ^+ v# T g
# 5
- [+ B" I+ i5 k6 ]) Sprint(G1[10]) # 返回与指定顶点相邻的所有顶点的属性
% C; Z9 P( m, _2 l8 y, s5 Q# {0: {'weight': 2.7}, 5: {}}" H5 w7 R. R- {1 }8 q) ~7 O, T3 n
print(G1.adj[10]) # 返回与指定顶点相邻的所有顶点的属性& ^$ H9 f5 R8 l) B) L3 N
# {0: {'weight': 2.7}, 5: {}}, Y1 S. W8 P3 x- I% \2 W
print(G1[1][2]) # 返回指定边的属性 f. B, I3 {+ F& P: ~
# {'weight': 3.6}
8 q1 S2 p1 e6 _0 [5 }9 kprint(G1.adj[1][2]) # 返回指定边的属性, _% P8 Q3 S9 k9 {/ U' w- y2 o/ \0 \
# {'weight': 3.6}
) L$ ^# ^0 }# O& S) Z/ z! d: Sprint(G1.degree(10)) # 返回指定顶点的度
7 E* l" E& W4 a$ W# }8 Z# 2
) U3 d& D* X3 l1 e! P2 [
9 U, r. m V' X, w! ~6 [( aprint('nx.info:',nx.info(G1)) # 返回图的基本信息9 p. Q! ]; t* b9 f# l" S" q9 c
print('nx.degree:',nx.degree(G1)) # 返回图中各顶点的度
% f z" A2 Z: O4 u) h, ~print('nx.density:',nx.degree_histogram(G1)) # 返回图中度的分布
, S7 y- S+ q8 \- T; q& Y0 a0 y! Aprint('nx.pagerank:',nx.pagerank(G1)) # 返回图中各顶点的频率分布
0 Z$ R( p8 b0 p5 {9 n1 O
& p7 Z3 e( B) F! f" J! z
3 _0 n1 U. \7 V% K/ J0 K- ^7 f' }7 o z( S% d
! C& I) U0 [* u8 m. V% t& S6 @
0 f9 _7 D7 Y2 t; _2.3 图的属性和方法图的方法
: [8 c' d7 W) u8 b& ~5 e% a2 Z$ F1 P% e, Q# R; P# q4 }$ x
方法 说明- Y+ y p% c5 ~: q/ T
G.has_node(n) 当图 G 中包括顶点 n 时返回 True2 \7 A! L' C8 S! E% Q( H
G.has_edge(u, v) 当图 G 中包括边 (u,v) 时返回 True+ Z- X" @3 Z' H' F* T0 [
G.number_of_nodes() 返回 图 G 中的顶点的数量
' [& P/ n8 C/ }# i5 f$ mG.number_of_edges() 返回 图 G 中的边的数量0 ^7 A$ W' ]; q5 ?* \ W
G.number_of_selfloops() 返回 图 G 中的自循环边的数量
0 f) y: [" c9 `3 U# s6 CG.degree([nbunch, weight]) 返回 图 G 中的全部顶点或指定顶点的度
6 v+ M* ]: |+ \, g0 xG.selfloop_edges([data, default]) 返回 图 G 中的全部的自循环边
6 W6 _9 U. J, T% \( @8 k$ J) `5 @G.subgraph([nodes]) 从图 G1中抽取顶点[nodes]及对应边构成的子图2 |7 t1 v- u- e W+ h
union(G1,G2) 合并图 G1、G2
3 M3 m6 f' T' p) [nx.info(G) 返回图的基本信息
1 i& W6 v8 x( Anx.degree(G) 返回图中各顶点的度
' T# v- j/ n% P- o4 Pnx.degree_histogram(G) 返回图中度的分布
8 }( p& d( ^' A0 S4 f5 q3 Z' vnx.pagerank(G) 返回图中各顶点的频率分布# F+ |" {* ^8 V& Q
nx.add_star(G,[nodes],**attr) 向图 G 添加星形网络
* y& [0 d) V, f' k3 pnx.add_path(G,[nodes],**attr) 向图 G 添加一条路径+ o1 J' B5 h. y% y- Y3 w' N8 O
nx.add_cycle(G,[nodes],**attr) 向图 G 添加闭合路径
7 I/ f9 P% B% Z! d" p6 z- ] Q& ]$ ?. B3 \
% ~1 D6 u' g+ O! M
例程:
" p% Y, `8 u, H& HG1.clear() # 清空图G1
% @0 j1 U* l) R knx.add_star(G1, [1, 2, 3, 4, 5], weight=1) # 添加星形网络:以第一个顶点为中心6 [) y! l0 p9 S
# [(1, 2), (1, 3), (1, 4), (1, 5)]$ m9 t) [2 X0 ? b* f. |& d
nx.add_path(G1, [5, 6, 8, 9, 10], weight=2) # 添加路径:顺序连接 n个节点的 n-1条边
0 p. V3 F- J" F* s# [(5, 6), (6, 8), (8, 9), (9, 10)]
& \5 t9 k! D$ knx.add_cycle(G1, [7, 8, 9, 10, 12], weight=3) # 添加闭合回路:循环连接 n个节点的 n 条边
+ U2 I, s0 B7 B- |; B# [(7, 8), (7, 12), (8, 9), (9, 10), (10, 12)]
: e3 l) T- `- ]: R3 `. bprint(G1.nodes) # 返回所有的顶点 [node1,...]
( K3 D* G/ i8 U. y( c$ xnx.draw_networkx(G1)
5 q$ D9 ?. d7 h4 X, I% ]! }8 B4 t; T0 lplt.show()7 M( B3 ^. ?9 ?. q
3 k% q! I0 C1 I, U9 y) q4 G! l
G2 = G1.subgraph([1, 2, 3, 8, 9, 10])" q* E7 B3 C/ Y8 w) g$ q
G3 = G1.subgraph([4, 5, 6, 7]), _2 n6 y: _$ }: o% q
G = nx.union(G2, G3)
7 F8 f, u/ ?) T/ | hprint(G.nodes) # 返回所有的顶点 [node1,...]
! [! M& `. O2 l6 C# [1, 2, 3, 8, 9, 10, 4, 5, 6, 7]2 g/ t$ h! v1 Q. o6 L0 H
/ B4 s. y f+ Z# d3 a+ t! l1 n
8 d! R9 t e) B6 A! P8 b9 x4 [3、图的绘制与分析3.1 图的绘制
F# A" ^9 Q# F4 j5 C8 ~" {8 O可视化是图论和网络问题中很重要的内容。NetworkX 在 Matplotlib、Graphviz 等图形工具包的基础上,提供了丰富的绘图功能。
; Z$ T7 _3 ]% g* @; M- f2 }# V5 s$ R8 q. [- F3 b8 Q
本系列拟对图和网络的可视化作一个专题,在此只简单介绍基于 Matplotlib 的基本绘图函数。基本绘图函数使用字典提供的位置将节点放置在散点图上,或者使用布局函数计算位置。
6 Z3 V/ V6 f5 w! }
9 Z; @2 }: }- [/ H0 v2 Z方法 说明
9 {5 p& _4 m' }6 z0 i1 x' ?draw(G[,pos,ax]) 基于 Matplotlib 绘制 图 G, ^# c# J$ Z" _" D: N1 L5 J- a
draw_networkx(G[, pos, arrows, with_labels]) 基于 Matplotlib 绘制 图 G
7 M2 m: Y3 G& y" [0 Qdraw_networkx_nodes(G, pos[, nodelist, . . . ]) 绘制图 G 的顶点
2 m$ ^8 V/ Q8 c2 ], z5 f2 a Tdraw_networkx_edges(G, pos[, edgelist, . . . ]) 绘制图 G 的边1 b, F* j5 _/ d: t `2 S0 a
draw_networkx_labels(G, pos[, labels, . . . ]) 绘制顶点的标签
+ Z3 d$ e$ E- K4 ddraw_networkx_edge_labels(G, pos[, . . . ]) 绘制边的标签
1 v0 @# p+ |% W
) C# O9 ~ A' ?
( E( q2 _ Z4 J* i$ W其中,nx.draw() 和 nx.draw_networkx() 是最基本的绘图函数,并可以通过自定义函数属性或其它绘图函数设置不同的绘图要求。
0 S. @9 [8 P- I! q/ udraw(G, pos=None, ax=None, **kwds) draw_networkx(G, pos=None, arrows=True, with_labels=True, **kwds)
B% e" g0 `9 `+ q9 a% z! s常用的属性定义如下:( a' B8 \. `4 e# S
5 k7 h& M; ^9 D) l8 Z‘node_size’:指定节点的尺寸大小,默认300
* F4 p8 {0 I* r8 x" U9 y- \‘node_color’:指定节点的颜色,默认红色) v( H! G/ g+ S t; I1 x$ ?1 d0 V
‘node_shape’:节点的形状,默认圆形0 K$ N* ]8 i7 H. [) F0 Q. Y
'‘alpha’:透明度,默认1.0,不透明4 ^. ^5 C8 u: l9 q6 j9 w
‘width’:边的宽度,默认1.02 q) k5 X7 {0 q- [
‘edge_color’:边的颜色,默认黑色
: j/ ^7 G. E, L6 D: B" ~' X- D‘style’:边的样式,可选 ‘solid’、‘dashed’、‘dotted’、‘dashdot’
; K I4 p3 c+ c2 u% y‘with_labels’:节点是否带标签,默认True
9 m6 ^7 B V9 Q8 Z& E0 N' N8 ~‘font_size’:节点标签字体大小,默认129 F7 |/ G! w2 U/ }6 K7 G; B
‘font_color’:节点标签字体颜色,默认黑色
$ ^1 R' r* ~3 C. o$ |$ `* B4 ], a7 O" W( e
' b# [2 h: ?) a5 d' }* X
3.2 图的分析NetwotkX 提供了图论函数对图的结构进行分析7 `. {3 L0 v% [" `8 `2 a$ z4 p
子图
- M0 n. Z- ~$ _% m- 子图是指顶点和边都分别是图 G 的顶点的子集和边的子集的图。
- subgraph()方法,按顶点从图 G 中抽出子图。例程如前。
5 F0 Z0 M3 @& j6 q. N0 z$ p 连通子图9 J) a& L2 x: v0 H- ^& ?6 @
, |) ?. u! S g# M: S; l- 如果图 G 中的任意两点间相互连通,则 G 是连通图。
- [color=rgba(0, 0, 0, 0.749019607843137)]connected_components()方法,返回连通子图的集合。
' o c0 K5 K" q, g! l* u4 E: 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}]/ D1 r2 ^/ V4 f
! {* `4 r [, d1 m3 J9 O, l2 ]' e4 W& D
2 r8 {" j. W; c. K+ W, c4 G/ I' e4 f
|