Python小白的数学建模课-图论的基本概念
" w6 p J# q" A P1 q# X. o8 y( `/ X' \. v9 {+ H. i* S
- 图论中所说的图,不是图形图像或地图,而是指由顶点和边所构成的图形结构。
- 图论不仅与拓扑学、计算机数据结构和算法密切相关,而且正在成为机器学习的关键技术。
- 本系列结合数学建模的应用需求,来介绍 NetworkX 图论与复杂网络工具包的基本功能和典型算法。) s% {+ ]+ A- J7 v
% w! q8 M' K+ Q) w: W* |, J2 X: W1. 图论1.1 图论是什么
' a5 o9 {8 p9 P4 x. t. b' n图论〔Graph Theory〕以图为研究对象,是离散数学的重要内容。图论不仅与拓扑学、计算机数据结构和算法密切相关,而且正在成为机器学习的关键技术。
/ Z: z' ^3 l; T; E. Q
: ~$ s2 y3 ~2 n8 G n* [. B图论中所说的图,不是指图形图像(image)或地图(map),而是指由顶点(vertex)和连接顶点的边(edge)所构成的关系结构。
8 j$ F- ?8 o$ \; B. t" S4 H9 D. K8 E
图提供了一种处理关系和交互等抽象概念的更好的方法,它还提供了直观的视觉方式来思考这些概念。
# O0 R2 t9 D9 o. L6 Z+ Y; ^) u5 i5 j }& s3 I$ U# z
1.2 NetworkX 工具包
$ q6 ]! @% m6 e- o1 u6 w& a$ JNetworkX 是基于 Python 语言的图论与复杂网络工具包,用于创建、操作和研究复杂网络的结构、动力学和功能。
6 A H% Z' Q0 C n
! `* k4 z7 `5 Q- {) Q. b' YNetworkX 可以以标准和非标准的数据格式描述图与网络,生成图与网络,分析网络结构,构建网络模型,设计网络算法,绘制网络图形。4 c/ w* ~; x1 p( ?% g( @
$ _* {. B/ ]& h# ^5 CNetworkX 提供了图形的类、对象、图形生成器、网络生成器、绘图工具,内置了常用的图论和网络分析算法,可以进行图和网络的建模、分析和仿真。% p5 i2 o$ \% Y2 S
! Z$ z* T3 }! V4 a: p% W6 X# O) g: t
NetworkX 的功能非常强大和庞杂,所涉及内容远远、远远地超出了数学建模的范围,甚至于很难进行系统的概括。本系列结合数学建模的应用需求,来介绍 NetworkX 图论与复杂网络工具包的基本功能和典型算法。
0 x$ q1 V; r+ p/ Y5 ~) n2 ~; G' B/ C3 x! j# `+ l
/ h. n2 F% m3 |, }6 }
2、图、顶点和边的创建与基本操作8 G/ W' A6 d+ g6 r
图由顶点和连接顶点的边构成,但与顶点的位置、边的曲直长短无关。 Networkx 支持创建简单无向图、有向图和多重图;内置许多标准的图论算法,节点可为任意数据;支持任意的边值维度,功能丰富,简单易用。 2.1 图的基本概念
8 f2 d0 j8 }9 q: q; ` G图(Graph):图是由若干顶点和连接顶点的边所构成关系结构。$ z: z& c, `( M# I& C
顶点(Node):图中的点称为顶点,也称节点。
1 ]& ^9 ^( D: M0 A l边(Edge):顶点之间的连线,称为边。0 P2 I4 c7 }; x! X3 Z5 |% K- r( K
平行边(Parallel edge):起点相同、终点也相同的两条边称为平行边。* j5 S6 |. i w$ n
循环(Cycle):起点和终点重合的边称为循环。
7 _% }2 _5 p0 ^% T1 p( v有向图(Digraph):图中的每条边都带有方向,称为有向图。
7 ~# o% D5 y; c$ t _无向图(Undirected graph):图中的每条边都没有方向,称为无向图。- I' }' z9 Z& E
赋权图(Weighted graph):图中的每条边都有一个或多个对应的参数,称为赋权图。该参数称为这条边的权,权可以用来表示两点间的距离、时间、费用。# M. \) o2 c: D/ V
度(Degree):与顶点相连的边的数量,称为该顶点的度。
$ _2 B4 C9 l! A) K/ e1 S
3 H! M, P* X% H9 v2.2 图、顶点和边的操作
q0 d4 w0 _$ ANetworkx很容易创建图、向图中添加顶点和边、从图中删除顶点和边,也可以查看、删除顶点和边的属性。
! L$ P- ?; h$ `) x5 _. p& P( |( ~9 F3 T" n
2.2.1 图的创建Graph() 类、DiGraph() 类、MultiGraph() 类和 MultiDiGraph() 类分别用来创建:无向图、有向图、多图和有向多图。定义和例程如下:# t* h$ \) o5 I7 X
! s4 y8 {$ W1 rclass Graph(incoming_graph_data=None, **attr)
- O5 g7 h! [- x9 aimport networkx as nx # 导入 NetworkX 工具包
* w7 n: T( T. Z$ F& e: B; C* E9 b! ?- U/ v C% V, L
# 创建 图 x( U% g( I" i; s0 I4 B# u0 }
G1 = nx.Graph() # 创建:空的 无向图, ]* }& i5 x+ _7 S$ p5 c
G2 = nx.DiGraph() #创建:空的 有向图0 o5 [$ ]& f( U* R* m1 ]. t" Q
G3 = nx.MultiGraph() #创建:空的 多图/ T3 B( W) f& u, Y: W* r2 S
G4 = nx.MultiDiGraph() #创建:空的 有向多图
3 T$ l+ u# F% g3 }
" Q* a/ z5 k3 n' @$ D( P
* ^7 U! w! C# a) y& u# ?2.2.2 顶点的添加、删除和查看% ?% I: G' M: K
图的每个顶点都有唯一的标签属性(label),可以用整数或字符类型表示,顶点还可以自定义任意属性。 顶点的常用操作:添加顶点,删除顶点,定义顶点属性,查看顶点和顶点属性。定义和例程如下:
: Q$ s- K/ f8 s- e/ p9 kGraph.add_node(node_for_adding, **attr)
0 a$ g: ~+ ~* L9 EGraph.add_nodes_from(nodes_for_adding, **attr)
, ~8 k! g1 C! G& j$ w- RGraph.remove_node(n)
( z; i, h' b/ C( s5 a+ v0 D4 PGraph.remove_nodes_from(nodes)3 B4 `( z; u L# O
$ i. i8 n* ?. ]# ]3 W
# 顶点(node)的操作: z. a7 r- S9 p1 \, i6 [
# 向图中添加顶点
& P: D) Y$ S, D" t; U# yG1.add_node(1) # 向 G1 添加顶点 14 S; D$ d9 {& L8 o7 A v
G1.add_node(1, name='n1', weight=1.0) # 添加顶点 1,定义 name, weight 属性. E- p4 ]) ?3 j# z/ u4 _9 g
G1.add_node(2, date='May-16') # 添加顶点 2,定义 time 属性1 S9 z, [6 T/ ?
G1.add_nodes_from([3, 0, 6], dist=1) # 添加多个顶点,并定义属性, {, A6 i6 S- b. M7 f; s" b
G1.add_nodes_from(range(10, 15)) # 向图 G1 添加顶点 10~14
; n# C3 N# I6 ~9 E( p: a0 i
# l4 u. y* o8 \8 a( E. z' V# 查看顶点和顶点属性
7 p3 }5 c6 n0 X0 u* Z' L! Pprint(G1.nodes()) # 查看顶点列表$ e) L9 C- a$ E
# [1, 2, 3, 0, 6, 10, 11, 12, 13, 14]! V( I: a/ L8 G% j
print(G1._node) # 查看顶点属性) P% \5 s5 n! T" l3 D
# {1: {'name': 'n1', 'weight': 1.0}, 2: {'date': 'May-16'}, 3: {'dist': 1}, 0: {'dist': 1}, 6: {'dist': 1}, 10: {}, 11: {}, 12: {}, 13: {}, 14: {}}
5 s! Q# ?8 f# g* P, ]
: F# ~# v$ @1 k7 c8 |# 从图中删除顶点
9 ?) I" w* i$ f5 i# \; fG1.remove_node(1) # 删除顶点
4 l$ V3 z. n0 v; n% z @2 JG1.remove_nodes_from([1, 11, 13, 14]) # 通过顶点标签的 list 删除多个顶点
* U5 s' I, K- ^7 n, aprint(G1.nodes()) # 查看顶点7 h Z+ s% l3 s2 E% y7 E- e% Y
# [2, 3, 0, 6, 10, 12] # 顶点列表
% C* _! O- x' F6 n6 a7 E' |2.2.3 边的添加、删除和查看边是两个顶点之间的连接,在 NetworkX 中 边是由对应顶点的名字的元组组成 e=(node1,node2)。边可以设置权重、关系等属性。 边的常用操作:添加边,删除边,定义边的属性,查看边和边的属性。向图中添加边时,如果边的顶点是图中不存在的,则自动向图中添加该顶点。 Graph.add_edge(u_of_edge, v_of_edge, **attr)
: o7 D* c: C# }5 F# t7 Y' f9 zGraph.add_edges_from(ebunch_to_add, **attr)% Y& k+ M5 M7 \
Graph.add_weighted_edges_from(ebunch_to_add, weight=‘weight’, **attr)
$ E1 V8 `6 I2 Q" V+ _8 I+ D6 U3 @) t8 d- ]# K' b
# 边(edge)的操作
. @: ^; L7 u) b' z# 向图中添加边% b, ^3 i) E4 @' m
G1.add_edge(1,5) # 向 G1 添加边,并自动添加图中没有的顶点 C3 P {, H( ~5 G
G1.add_edge(0,10, weight=2.7) # 向 G1 添加边,并设置边的属性2 |1 T J3 _: }% a& G/ ]
G1.add_edges_from([(1,2,{'weight':0}), (2,3,{'color':'blue'})]) # 向图中添加边,并设置属性3 ?. d9 R6 E9 q- E: N2 o9 P! m
G1.add_edges_from([(3,6),(1,2),(6,7),(5,10),(0,1)]) # 向图中添加多条边0 `) U9 D, {# x2 L( b2 e* u- _+ a
G1.add_weighted_edges_from([(1,2,3.6),[6,12,0.5]]) # 向图中添加多条赋权边: (node1,node2,weight)
7 B4 Q9 T# c1 P z# i5 K: dprint(G1.nodes()) # 查看顶点- I( e' F) s- D& Z. v& z
# [2, 3, 0, 6, 10, 12, 1, 5, 7] # 自动添加了图中没有的顶点
3 U0 C+ R- m6 |# a+ P% Y1 R
% n# u' _* v2 `# 从图中删除边
1 U' T) |6 S) {2 A) c6 bG1.remove_edge(0,1) # 从图中删除边 0-17 o, ?' P# ]4 a2 n Y4 u- n* y
G1.remove_edges_from([(2,3),(1,5),(6,7)]) # 从图中删除多条边
3 _; j; k" z2 J( X9 S2 T O9 W! i x! d% w
# 查看 边和边的属性8 [2 |( P, }/ P$ t2 ?
print(G1.edges) # 查看所有的边
* d3 Z. A9 F; ^1 C5 ~8 R8 B[(2, 1), (3, 6), (0, 10), (6, 12), (10, 5)]
* ~$ m+ p2 A3 u; L( fprint(G1.get_edge_data(1,2)) # 查看指定边的属性
) Q3 ?# Q1 W4 C# {'weight': 3.6}8 l8 v+ B! ~4 D' F8 ^2 H8 T
print(G1[1][2]) # 查看指定边的属性, ~/ p9 b! U6 W! ]1 R" H. _
# {'weight': 3.6}
0 P/ s/ C5 j. v* E* T# Sprint(G1.edges(data=True)) # 查看所有边的属性& P! J! ?' t, M
# [(2, 1, {'weight': 3.6}), (3, 6, {}), (0, 10, {'weight': 2.7}), (6, 12, {'weight': 0.5}), (10, 5, {})]
+ I! q2 w7 P6 S6 o$ Z) A% G5 _, e$ j* O* O
2.2.4 查看图、顶点和边的信息; }7 x5 [9 k7 z( l# w1 R
6 ~( N# X7 F: a0 u# 查看图、顶点和边的信息8 `- p, i, ], q P1 m" ?) z
print(G1.nodes) # 返回所有的顶点 [node1,...]9 o# b* |0 A' b" |4 I0 @
# [2, 3, 0, 6, 10, 12, 1, 5, 7]9 p+ L6 z$ l2 f; M$ e
print(G1.edges) # 返回所有的边 [(node1,node2),...]
0 K' v @" B* _6 ?3 a _# [(2, 1), (3, 6), (0, 10), (6, 12), (10, 5)]7 ?/ U! @/ K# f" x
print(G1.degree) # 返回各顶点的度 [(node1,degree1),...]
/ `; k6 W) P/ l# v) `5 ?5 q# [(2, 1), (3, 1), (0, 1), (6, 2), (10, 2), (12, 1), (1, 1), (5, 1), (7, 0)]
/ V7 |$ u7 N) r2 M: V% \. w6 _6 [print(G1.number_of_nodes()) # 返回顶点的数量; o7 Z2 X5 p+ {/ r; t( w
# 9
4 A$ X1 f/ M2 @2 b0 Lprint(G1.number_of_edges()) # 返回边的数量, o) i6 a% [7 z* h" s9 P: x
# 5
/ i4 Q1 S/ E, Eprint(G1[10]) # 返回与指定顶点相邻的所有顶点的属性7 ]. @3 F" ?- |, C& K( E& l
# {0: {'weight': 2.7}, 5: {}}
' N7 @( c5 Q# U2 yprint(G1.adj[10]) # 返回与指定顶点相邻的所有顶点的属性
a) {2 e6 a) A+ H3 M# {0: {'weight': 2.7}, 5: {}}* ~6 T3 F7 p% u9 q% c9 d
print(G1[1][2]) # 返回指定边的属性
' a( X A* p7 ~( k6 o! e# {'weight': 3.6}5 Y' A4 O# V7 G0 @& Z
print(G1.adj[1][2]) # 返回指定边的属性. i5 _; {+ C8 z* r- p# @
# {'weight': 3.6}3 R& Q3 x7 V/ g; s: B& ^
print(G1.degree(10)) # 返回指定顶点的度6 Z. Z' I+ _( Q) i' }1 y
# 2- X$ t3 q- f4 J+ y: M
& ]5 ]8 G9 i+ Qprint('nx.info:',nx.info(G1)) # 返回图的基本信息
5 j+ D* S9 n0 |4 mprint('nx.degree:',nx.degree(G1)) # 返回图中各顶点的度
6 S9 O3 W% V7 h6 q' {! vprint('nx.density:',nx.degree_histogram(G1)) # 返回图中度的分布) ~% _: p3 k. o, \: Z
print('nx.pagerank:',nx.pagerank(G1)) # 返回图中各顶点的频率分布
' C t3 f# e5 b j/ f) u5 P' g; {, m9 _" Q' r6 `5 y! i
9 ~% [6 }" ~7 i: K4 b+ S1 X: U* p1 k
: A- D+ w3 z/ V% e4 t$ N$ e1 ^4 K5 c8 e
2.3 图的属性和方法图的方法
4 ~. H3 F* ~% z8 x: s
5 v4 y0 o8 v4 \方法 说明) o- N' E- j- j# W0 R
G.has_node(n) 当图 G 中包括顶点 n 时返回 True
) x' v. {6 O+ w, d6 U0 a3 X$ zG.has_edge(u, v) 当图 G 中包括边 (u,v) 时返回 True
a3 g* v3 n( h9 b5 ~0 q8 f! L; nG.number_of_nodes() 返回 图 G 中的顶点的数量8 E$ z+ C4 N( u+ N$ v+ h( X5 z( U
G.number_of_edges() 返回 图 G 中的边的数量
& R x; b& q/ @. FG.number_of_selfloops() 返回 图 G 中的自循环边的数量
9 ]+ f$ m& d2 e+ A# e+ w. iG.degree([nbunch, weight]) 返回 图 G 中的全部顶点或指定顶点的度
) d( ~$ f' u6 iG.selfloop_edges([data, default]) 返回 图 G 中的全部的自循环边1 R; F3 x, L% c/ }( t
G.subgraph([nodes]) 从图 G1中抽取顶点[nodes]及对应边构成的子图; c3 X# w- m1 X& J' ^; _* Y3 K2 q) Y) {
union(G1,G2) 合并图 G1、G25 g3 `* {$ z: w# H% m' G/ Z7 H
nx.info(G) 返回图的基本信息
9 O$ x, W+ a# s' f" t7 n4 } bnx.degree(G) 返回图中各顶点的度
. c% F. S; c1 s$ a- R, J8 |nx.degree_histogram(G) 返回图中度的分布
: e; R" K# i' d& J5 X& n0 gnx.pagerank(G) 返回图中各顶点的频率分布
0 o. e( H; v+ ?& i" ^& Mnx.add_star(G,[nodes],**attr) 向图 G 添加星形网络& o1 @1 E; w7 P) E7 p" `" E: _% W
nx.add_path(G,[nodes],**attr) 向图 G 添加一条路径( W& C, p' {7 b! z9 ?8 h' b2 {7 b
nx.add_cycle(G,[nodes],**attr) 向图 G 添加闭合路径
5 s3 J9 I4 d) l1 K- M- b
6 _" W9 H2 p5 e9 n& T X: T, D/ |9 p5 T6 J4 o8 I; P
例程:- K' o7 B, U. q. W. F, D" [+ E& Z' \2 \
G1.clear() # 清空图G1: O" [# k0 ? h
nx.add_star(G1, [1, 2, 3, 4, 5], weight=1) # 添加星形网络:以第一个顶点为中心
% N2 u4 V& B/ e6 ^# [(1, 2), (1, 3), (1, 4), (1, 5)]1 _' o) I8 z. u% @* X5 P
nx.add_path(G1, [5, 6, 8, 9, 10], weight=2) # 添加路径:顺序连接 n个节点的 n-1条边
+ N" j! r1 R N! e# [(5, 6), (6, 8), (8, 9), (9, 10)]
$ a" p% N3 @+ p4 S3 t; Cnx.add_cycle(G1, [7, 8, 9, 10, 12], weight=3) # 添加闭合回路:循环连接 n个节点的 n 条边
+ }8 }9 V# n: O; v2 E# [(7, 8), (7, 12), (8, 9), (9, 10), (10, 12)]: v+ Z* \' m, t0 i5 R
print(G1.nodes) # 返回所有的顶点 [node1,...]4 e$ j$ A5 K- J$ j
nx.draw_networkx(G1)
! ~3 f' P" [- m: _8 |. e' Tplt.show()
8 k+ N$ D4 o% H' [7 L4 `* h* \( u
7 J* ]. E( ^5 ?; R& OG2 = G1.subgraph([1, 2, 3, 8, 9, 10])
4 {5 [2 e& ~' g; s7 PG3 = G1.subgraph([4, 5, 6, 7])
. C$ }1 V1 t) P) GG = nx.union(G2, G3)/ E8 w. ~- r: p& z' Z; ^+ w" D# ^: v
print(G.nodes) # 返回所有的顶点 [node1,...]
; i( E1 R0 q& C% G8 D2 [# [1, 2, 3, 8, 9, 10, 4, 5, 6, 7]
! n/ G) `: L; h7 Z4 X
7 I: q \0 d3 ~% o7 H' h" }& e) e+ s, w# b9 y
3、图的绘制与分析3.1 图的绘制
X% S% i# t: e. B. I$ N可视化是图论和网络问题中很重要的内容。NetworkX 在 Matplotlib、Graphviz 等图形工具包的基础上,提供了丰富的绘图功能。
3 p3 X# r, h: g5 D3 A2 {2 Z( b; r
: S' G# |- b1 x7 {% Y9 i. r9 Q本系列拟对图和网络的可视化作一个专题,在此只简单介绍基于 Matplotlib 的基本绘图函数。基本绘图函数使用字典提供的位置将节点放置在散点图上,或者使用布局函数计算位置。
) h. z' g" {4 X S2 q4 l: Y8 x, B7 |* K0 Z4 R* N; j
方法 说明& |' O7 |' y, }( ?4 @
draw(G[,pos,ax]) 基于 Matplotlib 绘制 图 G1 j( z K8 i+ m: V
draw_networkx(G[, pos, arrows, with_labels]) 基于 Matplotlib 绘制 图 G
* f: x' N; q* f1 G4 edraw_networkx_nodes(G, pos[, nodelist, . . . ]) 绘制图 G 的顶点9 a* F1 @# \8 i- A$ j/ V1 N4 P
draw_networkx_edges(G, pos[, edgelist, . . . ]) 绘制图 G 的边
3 @+ p2 `: O. X5 wdraw_networkx_labels(G, pos[, labels, . . . ]) 绘制顶点的标签# @8 p9 ?5 a+ |4 h7 x" q
draw_networkx_edge_labels(G, pos[, . . . ]) 绘制边的标签" q: k& ]* ]7 k% t: t
3 ?9 ?. ^8 H" f
* w1 S, r v+ g& j3 q9 ]其中,nx.draw() 和 nx.draw_networkx() 是最基本的绘图函数,并可以通过自定义函数属性或其它绘图函数设置不同的绘图要求。
' u% [7 C* A6 W3 i. P+ [draw(G, pos=None, ax=None, **kwds) draw_networkx(G, pos=None, arrows=True, with_labels=True, **kwds)
6 i; e$ t: R; _8 M* W7 d- l常用的属性定义如下:
4 U! d* D5 Y7 K' c
$ N, I: M7 Y# @7 T! ]& T, z‘node_size’:指定节点的尺寸大小,默认300/ c, o& ~3 I! L# J; v8 o7 [" g
‘node_color’:指定节点的颜色,默认红色$ U7 d) L; e8 G/ {+ `
‘node_shape’:节点的形状,默认圆形
/ S% G6 n- f* i& Q& ]6 S'‘alpha’:透明度,默认1.0,不透明
& @- w7 Z( K) O# e, X4 I‘width’:边的宽度,默认1.0
2 x$ Z7 c4 e" | A9 b‘edge_color’:边的颜色,默认黑色* ?7 M2 _# p; L9 z0 H4 {6 o
‘style’:边的样式,可选 ‘solid’、‘dashed’、‘dotted’、‘dashdot’/ ?. v( S) H8 G. O e4 w
‘with_labels’:节点是否带标签,默认True; W& K8 \. p, P* \! a; j
‘font_size’:节点标签字体大小,默认12. H* }4 t! B; [" E t
‘font_color’:节点标签字体颜色,默认黑色
3 {$ v9 ?- b7 }
8 b3 F" t9 r3 t1 x% H. J . Q/ v3 w2 R0 U& F. Y; F- {8 \
3.2 图的分析NetwotkX 提供了图论函数对图的结构进行分析
0 `# k5 x7 A0 y9 ]" L子图
{; [, \ x1 S! O- 子图是指顶点和边都分别是图 G 的顶点的子集和边的子集的图。
- subgraph()方法,按顶点从图 G 中抽出子图。例程如前。
% v- K' o' e2 M2 a; O 连通子图 j& A% _* J2 g' d& o A! B
9 W5 W! J3 M& l6 r
- 如果图 G 中的任意两点间相互连通,则 G 是连通图。
- [color=rgba(0, 0, 0, 0.749019607843137)]connected_components()方法,返回连通子图的集合。
2 h, t+ Y: L1 `[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}]+ h! F0 }& k1 U# p$ U+ i
( w) n$ U' M& [6 d, d: _
2 d7 U) K* V' w% C1 ^$ @0 i
2 U( \9 b; C" s( J/ V0 M: n$ P3 G, n/ y: X0 w, Q4 B4 K; D
|