Python小白的数学建模课-图论的基本概念
8 J- B* P2 {" h+ Y; M" I$ C/ R- U+ u5 f# {' Q; d
- 图论中所说的图,不是图形图像或地图,而是指由顶点和边所构成的图形结构。
- 图论不仅与拓扑学、计算机数据结构和算法密切相关,而且正在成为机器学习的关键技术。
- 本系列结合数学建模的应用需求,来介绍 NetworkX 图论与复杂网络工具包的基本功能和典型算法。) c! k: k5 ~ g7 t+ H
, w( H$ y1 l) \* V: i( `& j* t
1. 图论1.1 图论是什么 O( r0 W1 l! [4 X
图论〔Graph Theory〕以图为研究对象,是离散数学的重要内容。图论不仅与拓扑学、计算机数据结构和算法密切相关,而且正在成为机器学习的关键技术。! Y0 Q8 F' N9 m, i8 z- B
/ v0 D; Q# v* v图论中所说的图,不是指图形图像(image)或地图(map),而是指由顶点(vertex)和连接顶点的边(edge)所构成的关系结构。3 O, M" Z$ q* N
2 n- |( L7 ]; ~图提供了一种处理关系和交互等抽象概念的更好的方法,它还提供了直观的视觉方式来思考这些概念。
' u7 t2 I, f! O, I) _9 A
o: l) p+ @$ Q' k0 X/ y' l1.2 NetworkX 工具包" ?9 f9 y! A# E7 w- @
NetworkX 是基于 Python 语言的图论与复杂网络工具包,用于创建、操作和研究复杂网络的结构、动力学和功能。
1 Q- @) X& o5 @9 A& N2 i6 C. i) w
NetworkX 可以以标准和非标准的数据格式描述图与网络,生成图与网络,分析网络结构,构建网络模型,设计网络算法,绘制网络图形。7 I* {6 T% j1 [
' t, \+ n. I4 |+ `, e
NetworkX 提供了图形的类、对象、图形生成器、网络生成器、绘图工具,内置了常用的图论和网络分析算法,可以进行图和网络的建模、分析和仿真。
( h2 s% Z% n* \; v! A
- a* t& S* U& Z2 G. ANetworkX 的功能非常强大和庞杂,所涉及内容远远、远远地超出了数学建模的范围,甚至于很难进行系统的概括。本系列结合数学建模的应用需求,来介绍 NetworkX 图论与复杂网络工具包的基本功能和典型算法。
( }/ q# [7 }( o5 x5 M6 D
& ~* F' _5 `. h4 x8 ?9 W0 E / }/ o) r9 B4 S. z3 g7 c1 D
2、图、顶点和边的创建与基本操作
& T8 e, g% g/ i$ X2 u! M7 X0 q图由顶点和连接顶点的边构成,但与顶点的位置、边的曲直长短无关。 Networkx 支持创建简单无向图、有向图和多重图;内置许多标准的图论算法,节点可为任意数据;支持任意的边值维度,功能丰富,简单易用。 2.1 图的基本概念
( x. a# X' T; c$ G8 h- v& K图(Graph):图是由若干顶点和连接顶点的边所构成关系结构。% Y$ c0 o+ Q8 [1 E
顶点(Node):图中的点称为顶点,也称节点。+ W X+ G# c4 }+ i
边(Edge):顶点之间的连线,称为边。9 W$ H1 M0 @+ Z4 |) m% S: c
平行边(Parallel edge):起点相同、终点也相同的两条边称为平行边。4 J5 c) S2 t/ Y/ c/ F
循环(Cycle):起点和终点重合的边称为循环。/ H9 A$ ^1 K' T9 x
有向图(Digraph):图中的每条边都带有方向,称为有向图。* X7 b: j1 F" `& |
无向图(Undirected graph):图中的每条边都没有方向,称为无向图。
/ y" X! J ~/ W3 D3 A赋权图(Weighted graph):图中的每条边都有一个或多个对应的参数,称为赋权图。该参数称为这条边的权,权可以用来表示两点间的距离、时间、费用。/ [5 [0 N' H$ L( t2 u
度(Degree):与顶点相连的边的数量,称为该顶点的度。
h* u% B5 P' u) b% S
- F. i$ t2 e* p6 d2.2 图、顶点和边的操作4 ?: I# l& a1 b' S0 e8 G
Networkx很容易创建图、向图中添加顶点和边、从图中删除顶点和边,也可以查看、删除顶点和边的属性。
5 z8 ~$ \7 t& b. l5 n. H0 [* u) T8 J. P& C' t, s" ]
2.2.1 图的创建Graph() 类、DiGraph() 类、MultiGraph() 类和 MultiDiGraph() 类分别用来创建:无向图、有向图、多图和有向多图。定义和例程如下:
" b; `" B# _. r: q& w6 H; I7 J# O6 e9 [) b1 f; W1 ^3 @
class Graph(incoming_graph_data=None, **attr)
$ A8 c, J8 ^/ n8 I: x t1 L4 `* _import networkx as nx # 导入 NetworkX 工具包# ?5 E% M8 X f4 ?9 e3 ^
4 M' ~1 A$ q3 i- n4 r# 创建 图
0 N; S6 h8 @' n# y, o( Q H5 F" ?G1 = nx.Graph() # 创建:空的 无向图1 {- j; a! r n6 `; v: [ e$ G1 W
G2 = nx.DiGraph() #创建:空的 有向图, ~4 H# p) }" [
G3 = nx.MultiGraph() #创建:空的 多图
" z/ \5 p! E1 w2 o, D: dG4 = nx.MultiDiGraph() #创建:空的 有向多图
( m6 p! E& ~/ U# N6 `+ i
+ {, U' t9 K% W o0 G$ b
" [2 W0 t) P' |1 T2.2.2 顶点的添加、删除和查看/ x$ |* @# n' ]# }; l! V
图的每个顶点都有唯一的标签属性(label),可以用整数或字符类型表示,顶点还可以自定义任意属性。 顶点的常用操作:添加顶点,删除顶点,定义顶点属性,查看顶点和顶点属性。定义和例程如下: # J& Y H5 U4 o8 `+ m
Graph.add_node(node_for_adding, **attr) U) R2 t3 d+ f
Graph.add_nodes_from(nodes_for_adding, **attr)
; g8 l! a( S( K$ u; l5 VGraph.remove_node(n)" q$ `1 q" w9 z% z; R8 N
Graph.remove_nodes_from(nodes)! \% ] Q D1 m
" ~/ d! Q* X0 `( l
# 顶点(node)的操作
# K8 D/ y8 @9 t; f) ^5 {: k7 k9 L# 向图中添加顶点
7 k' I \( X& \7 C0 iG1.add_node(1) # 向 G1 添加顶点 18 Y4 {, f$ z9 |6 `0 ~$ A
G1.add_node(1, name='n1', weight=1.0) # 添加顶点 1,定义 name, weight 属性2 u3 \. O( v4 a1 z8 y
G1.add_node(2, date='May-16') # 添加顶点 2,定义 time 属性
& s% i0 N# H6 Q, ]7 L5 L( a6 d& R1 |G1.add_nodes_from([3, 0, 6], dist=1) # 添加多个顶点,并定义属性5 \* u, _: w, A
G1.add_nodes_from(range(10, 15)) # 向图 G1 添加顶点 10~147 [, E& E, X" P
$ s1 L$ B+ ~, b, \# 查看顶点和顶点属性
+ ~6 X5 F0 e9 kprint(G1.nodes()) # 查看顶点列表
# r' p; ~4 `; R3 l) }8 ~9 {# [1, 2, 3, 0, 6, 10, 11, 12, 13, 14]
* i9 j2 t( b0 f$ U6 S; B. k3 bprint(G1._node) # 查看顶点属性" l9 f. e T: m: e- q/ W# u
# {1: {'name': 'n1', 'weight': 1.0}, 2: {'date': 'May-16'}, 3: {'dist': 1}, 0: {'dist': 1}, 6: {'dist': 1}, 10: {}, 11: {}, 12: {}, 13: {}, 14: {}}* o) Y# _3 t3 R' T. v$ V- \1 p
- w* T4 j& [/ E/ m7 Z& k6 @/ H
# 从图中删除顶点
) }3 k/ |6 r C% @$ `G1.remove_node(1) # 删除顶点
* H7 ^- |5 u) b. [G1.remove_nodes_from([1, 11, 13, 14]) # 通过顶点标签的 list 删除多个顶点1 e: j1 c1 W' e' ^, R8 O& X$ H
print(G1.nodes()) # 查看顶点
# G5 }3 y! Y* e$ S8 N. r$ E9 D# [2, 3, 0, 6, 10, 12] # 顶点列表
+ A H6 X7 X+ T/ F2.2.3 边的添加、删除和查看边是两个顶点之间的连接,在 NetworkX 中 边是由对应顶点的名字的元组组成 e=(node1,node2)。边可以设置权重、关系等属性。 边的常用操作:添加边,删除边,定义边的属性,查看边和边的属性。向图中添加边时,如果边的顶点是图中不存在的,则自动向图中添加该顶点。 Graph.add_edge(u_of_edge, v_of_edge, **attr): | M/ V. E- ^2 v
Graph.add_edges_from(ebunch_to_add, **attr)* q8 f7 f/ K: L" _/ i1 u+ G% I9 U
Graph.add_weighted_edges_from(ebunch_to_add, weight=‘weight’, **attr)7 z$ [* a; u# U
$ j7 ?7 |+ u- ~8 U5 Y# 边(edge)的操作
% [# A( T2 _& s0 I# J# 向图中添加边
$ ~$ H! e O1 j% d0 ]- HG1.add_edge(1,5) # 向 G1 添加边,并自动添加图中没有的顶点6 y. e5 P1 N4 \
G1.add_edge(0,10, weight=2.7) # 向 G1 添加边,并设置边的属性
6 `0 c( y/ J$ N4 k/ B7 Q, O3 @G1.add_edges_from([(1,2,{'weight':0}), (2,3,{'color':'blue'})]) # 向图中添加边,并设置属性
2 N7 V& z" M( a1 h9 X# UG1.add_edges_from([(3,6),(1,2),(6,7),(5,10),(0,1)]) # 向图中添加多条边
$ ^7 C+ g7 g. E9 HG1.add_weighted_edges_from([(1,2,3.6),[6,12,0.5]]) # 向图中添加多条赋权边: (node1,node2,weight)
0 T$ C% i1 s6 c9 eprint(G1.nodes()) # 查看顶点
2 z3 \3 L0 V% H0 J, n4 T2 o2 p6 v# [2, 3, 0, 6, 10, 12, 1, 5, 7] # 自动添加了图中没有的顶点
! t# V$ U, Z# P! g d
! S+ m/ B& _) ^3 s5 F# 从图中删除边, Y' M& ]" E$ l3 Q
G1.remove_edge(0,1) # 从图中删除边 0-1
: s' p3 `) `- u1 k0 W; U1 {1 MG1.remove_edges_from([(2,3),(1,5),(6,7)]) # 从图中删除多条边
1 D; u; ?0 p/ d
3 |- k3 e Y4 P9 D# O/ e! \3 X# 查看 边和边的属性
5 z6 J- z4 O8 ^% ~9 t; aprint(G1.edges) # 查看所有的边
- w* `6 y) d% W[(2, 1), (3, 6), (0, 10), (6, 12), (10, 5)]
% k% h! N s( k# ~4 q/ P; U& O0 X6 fprint(G1.get_edge_data(1,2)) # 查看指定边的属性
& W) T+ b: P e! s6 ?# {'weight': 3.6}
+ y; c# n" i# H: o! Xprint(G1[1][2]) # 查看指定边的属性. }" w4 x% ]7 s; }
# {'weight': 3.6}
1 p, z, u% z" _- d4 \% _print(G1.edges(data=True)) # 查看所有边的属性
/ ~- w7 w" Z& c6 n$ A+ t. D# [(2, 1, {'weight': 3.6}), (3, 6, {}), (0, 10, {'weight': 2.7}), (6, 12, {'weight': 0.5}), (10, 5, {})]3 \7 [) u: o- D l$ j2 K
( L2 l; Q% |, x* T# m& C
2.2.4 查看图、顶点和边的信息
5 H- G7 B2 R, j
, ~+ n+ W9 l4 l! b2 h' a" z, q' P# 查看图、顶点和边的信息
( w4 b3 T% L% b( xprint(G1.nodes) # 返回所有的顶点 [node1,...]% p: h: |* u, W# s
# [2, 3, 0, 6, 10, 12, 1, 5, 7]
0 L2 J6 |: A6 A. \( f6 y+ h7 f( vprint(G1.edges) # 返回所有的边 [(node1,node2),...]: ^5 A5 }, p: v3 r' X- Q
# [(2, 1), (3, 6), (0, 10), (6, 12), (10, 5)]; q) i6 w E. k# k9 g; A( o0 X& h
print(G1.degree) # 返回各顶点的度 [(node1,degree1),...]
( R) c5 ?) m9 \- f* |# [(2, 1), (3, 1), (0, 1), (6, 2), (10, 2), (12, 1), (1, 1), (5, 1), (7, 0)]- v5 |" T9 `. i0 {: g
print(G1.number_of_nodes()) # 返回顶点的数量9 e: j* i. j0 J; Q6 ]5 y
# 92 b2 |. x3 O l: k
print(G1.number_of_edges()) # 返回边的数量+ t* O. x- C0 l- z8 t% Q u
# 5* W" @) \- w v& I' C. d* r) q
print(G1[10]) # 返回与指定顶点相邻的所有顶点的属性
) x: w8 C" b7 |# {0: {'weight': 2.7}, 5: {}}. l* C: \4 L- B. b7 Z
print(G1.adj[10]) # 返回与指定顶点相邻的所有顶点的属性
/ \' o5 x- S, S* f5 k# {0: {'weight': 2.7}, 5: {}}
) `( p- ~ s8 M5 l" E6 r2 l$ Jprint(G1[1][2]) # 返回指定边的属性2 Y6 H* Y j) |, W9 Q1 M4 J
# {'weight': 3.6}
$ j( Q! s: K0 u% g! m6 D! mprint(G1.adj[1][2]) # 返回指定边的属性
$ H, P6 S( {" f# Z' }$ o# {'weight': 3.6}
0 [ ?4 @8 o& Q" N. w7 N6 Gprint(G1.degree(10)) # 返回指定顶点的度
/ N! R5 X/ ]" |$ S# 2& |# D! ]& V6 j+ S$ c6 ?% \
( J1 v6 \1 _) [. J e- \ S: w
print('nx.info:',nx.info(G1)) # 返回图的基本信息- a" {# ] T6 w
print('nx.degree:',nx.degree(G1)) # 返回图中各顶点的度. ]5 E# a; q( A; ?
print('nx.density:',nx.degree_histogram(G1)) # 返回图中度的分布
% N2 B& O' ]8 I+ T/ k2 Z5 wprint('nx.pagerank:',nx.pagerank(G1)) # 返回图中各顶点的频率分布
( c/ e/ p( U1 b4 W2 M0 V+ b6 ~/ f5 z8 ]/ f' I2 c
( [) \) i9 @$ r3 d8 m- B# c0 T9 K2 R1 A# M
2 t$ g" k" G8 I* u+ i. C5 E
# l, s* T+ ]& ]5 t; L5 ]2.3 图的属性和方法图的方法+ G* {) q; q2 Y+ a$ W. D
; d7 Q( [" p2 P& r7 w8 N9 |
方法 说明
8 \0 z6 `% D- y, D9 R" QG.has_node(n) 当图 G 中包括顶点 n 时返回 True
2 C g: Y% z% R- ?* j- X! DG.has_edge(u, v) 当图 G 中包括边 (u,v) 时返回 True* r, [2 K) Q0 [* M: o5 v( v
G.number_of_nodes() 返回 图 G 中的顶点的数量! b$ [& u+ z# D0 D! l& K" ]
G.number_of_edges() 返回 图 G 中的边的数量: [1 d/ a) q2 a2 C" E- [
G.number_of_selfloops() 返回 图 G 中的自循环边的数量
5 V1 z6 y4 R w: u% j- i: JG.degree([nbunch, weight]) 返回 图 G 中的全部顶点或指定顶点的度
$ B- G: X. k s! z- v0 `) u5 LG.selfloop_edges([data, default]) 返回 图 G 中的全部的自循环边
2 i. O3 N, T# J2 E' HG.subgraph([nodes]) 从图 G1中抽取顶点[nodes]及对应边构成的子图& ]5 ?, u* m. c& S! ]; m
union(G1,G2) 合并图 G1、G2
$ p0 C( L3 y. d* \nx.info(G) 返回图的基本信息
9 a+ o. p! y, f+ c9 E* Gnx.degree(G) 返回图中各顶点的度
& y! e4 w. a% x4 m8 V! k' r% gnx.degree_histogram(G) 返回图中度的分布
' `: @, t5 N: V, P! gnx.pagerank(G) 返回图中各顶点的频率分布4 B. G3 E; H: H
nx.add_star(G,[nodes],**attr) 向图 G 添加星形网络$ e) j# o& h9 h* G
nx.add_path(G,[nodes],**attr) 向图 G 添加一条路径
0 Q( z9 ]9 ?9 M7 ]6 hnx.add_cycle(G,[nodes],**attr) 向图 G 添加闭合路径
* p9 U$ o+ S& O% |) z# O
1 X8 c8 i* Y2 j" ?& ^8 @2 S8 Y( ]0 w4 x2 F" h8 ]
例程:( B* g0 W+ U, i, N; U! y' d
G1.clear() # 清空图G10 ?4 }2 S& H; @' M, Q" t
nx.add_star(G1, [1, 2, 3, 4, 5], weight=1) # 添加星形网络:以第一个顶点为中心
. F3 O3 Z! x: r' y, f/ N# R. e# [(1, 2), (1, 3), (1, 4), (1, 5)]
. J6 g# l: S5 t9 c* X% |5 j. _nx.add_path(G1, [5, 6, 8, 9, 10], weight=2) # 添加路径:顺序连接 n个节点的 n-1条边
" G/ i5 C( o7 i$ @+ L# [(5, 6), (6, 8), (8, 9), (9, 10)]
3 t6 z1 \- J5 \nx.add_cycle(G1, [7, 8, 9, 10, 12], weight=3) # 添加闭合回路:循环连接 n个节点的 n 条边' X( z3 [1 i+ c7 e
# [(7, 8), (7, 12), (8, 9), (9, 10), (10, 12)]
4 f% y# {% J5 ?! {1 p) R7 Gprint(G1.nodes) # 返回所有的顶点 [node1,...]
% \: i8 D+ G: e, Q) cnx.draw_networkx(G1)5 v/ a7 P" n. N2 O9 d
plt.show()
; b t/ d( j5 R, Y" ]3 |" x2 m u7 t" U* U/ \
G2 = G1.subgraph([1, 2, 3, 8, 9, 10])# r( O$ i8 W9 b
G3 = G1.subgraph([4, 5, 6, 7])0 \0 y+ f8 `1 C; U o! k
G = nx.union(G2, G3)- D/ T, N+ ?3 o _% h! A
print(G.nodes) # 返回所有的顶点 [node1,...]
8 [4 V/ E0 D; L# [1, 2, 3, 8, 9, 10, 4, 5, 6, 7]
8 C/ {0 Q, _3 u* I0 _# t8 k( `0 ?7 k) B8 o; J! ~+ b
. w8 H# o( d# k% \% o# }4 j& A
3、图的绘制与分析3.1 图的绘制
; F" P2 F* L6 E) F5 `" u1 R可视化是图论和网络问题中很重要的内容。NetworkX 在 Matplotlib、Graphviz 等图形工具包的基础上,提供了丰富的绘图功能。4 K& j, k2 I& Q( c4 Z" ~, X
+ a0 i& ?! v% i _9 R- }本系列拟对图和网络的可视化作一个专题,在此只简单介绍基于 Matplotlib 的基本绘图函数。基本绘图函数使用字典提供的位置将节点放置在散点图上,或者使用布局函数计算位置。
, [( R8 b6 d z- R: n, v ~+ e+ w4 B. t. G
方法 说明
, M, w/ {6 `4 p/ U& |2 |draw(G[,pos,ax]) 基于 Matplotlib 绘制 图 G
: t: h: M/ {/ g8 d6 \1 bdraw_networkx(G[, pos, arrows, with_labels]) 基于 Matplotlib 绘制 图 G* r0 O& P# h; J+ W' f! r
draw_networkx_nodes(G, pos[, nodelist, . . . ]) 绘制图 G 的顶点
) I, Q' B+ {* Y) T/ Adraw_networkx_edges(G, pos[, edgelist, . . . ]) 绘制图 G 的边% m6 i6 j2 s* o
draw_networkx_labels(G, pos[, labels, . . . ]) 绘制顶点的标签
( K0 N ]& K# n: U vdraw_networkx_edge_labels(G, pos[, . . . ]) 绘制边的标签, x- B: m6 |$ F! n
& ^- h2 J0 \( |0 Z5 C7 ]. U1 g) R% ] Q
" W4 W) j5 O2 g2 z& d7 S7 ?: i. k
其中,nx.draw() 和 nx.draw_networkx() 是最基本的绘图函数,并可以通过自定义函数属性或其它绘图函数设置不同的绘图要求。
4 \1 n$ v8 x# b% a( ~; i' Pdraw(G, pos=None, ax=None, **kwds) draw_networkx(G, pos=None, arrows=True, with_labels=True, **kwds) ) C9 b7 c( {8 j* ?) O
常用的属性定义如下:
5 B) I) _3 V8 A2 k r _' H+ r* ?8 \
‘node_size’:指定节点的尺寸大小,默认300
; M$ g3 V0 j5 ?5 M% p$ g‘node_color’:指定节点的颜色,默认红色7 v3 M2 [2 B2 f: K8 `
‘node_shape’:节点的形状,默认圆形
0 _9 O* p; g' I, e% w'‘alpha’:透明度,默认1.0,不透明
( A' d2 ~ M1 \7 O( A‘width’:边的宽度,默认1.0& i# J' J* h) z7 ]
‘edge_color’:边的颜色,默认黑色+ D: X/ x( Z. s9 G% D! I' d6 m
‘style’:边的样式,可选 ‘solid’、‘dashed’、‘dotted’、‘dashdot’1 m8 t/ a2 v% u$ l5 L1 l* @
‘with_labels’:节点是否带标签,默认True
1 \2 D, Q5 T; U& O‘font_size’:节点标签字体大小,默认12( ]! b% P2 H0 r' M5 I6 O2 {2 r
‘font_color’:节点标签字体颜色,默认黑色 o3 c+ N+ i, i0 |, n4 Q5 @
+ n6 f- z5 e( A+ F E1 O" R$ w0 Z![]()
+ a, Z) B# ?) M- t0 f. o1 N4 U' q3.2 图的分析NetwotkX 提供了图论函数对图的结构进行分析
- C' j0 A) N4 I+ Q子图% K5 P0 G: [: D: a6 m, J& l; \
- 子图是指顶点和边都分别是图 G 的顶点的子集和边的子集的图。
- subgraph()方法,按顶点从图 G 中抽出子图。例程如前。
( E1 ~' J3 E' Q2 [% h" h 连通子图
. ^5 c" `$ i' k0 F6 o8 @7 ?8 N
# w( D9 b; |! o0 ?) p! I/ R2 P- 如果图 G 中的任意两点间相互连通,则 G 是连通图。
- [color=rgba(0, 0, 0, 0.749019607843137)]connected_components()方法,返回连通子图的集合。" m; p+ q7 Q/ ~5 E5 H# L
[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}]
/ R3 a7 j3 _( Y! I. T+ i2 Q ) x) k; n! i. ]1 W
6 J$ q' x9 d" d* L2 ~
/ s" Q* {" p( V% r( I
; W, P! z& a& g9 V |