Python小白的数学建模课-图论的基本概念
1 B' j& L8 D# X
3 p9 h9 p: L7 L1 K- 图论中所说的图,不是图形图像或地图,而是指由顶点和边所构成的图形结构。
- 图论不仅与拓扑学、计算机数据结构和算法密切相关,而且正在成为机器学习的关键技术。
- 本系列结合数学建模的应用需求,来介绍 NetworkX 图论与复杂网络工具包的基本功能和典型算法。
8 ~# s5 @3 |! M$ e5 U$ X4 g0 J9 Q
8 m8 ` A0 h3 L# _1 z% M' c' l1. 图论1.1 图论是什么
; h# }# Z* H4 \- f* D. L图论〔Graph Theory〕以图为研究对象,是离散数学的重要内容。图论不仅与拓扑学、计算机数据结构和算法密切相关,而且正在成为机器学习的关键技术。
' ~0 i% [& c, l8 ^- i! k p1 Y3 z2 F- {0 U) T
图论中所说的图,不是指图形图像(image)或地图(map),而是指由顶点(vertex)和连接顶点的边(edge)所构成的关系结构。
1 m. r5 f( x8 k% u2 a0 i/ i" f, Z& g3 u, {7 P u& c
图提供了一种处理关系和交互等抽象概念的更好的方法,它还提供了直观的视觉方式来思考这些概念。
- }& y. w! X0 [. R8 F
" m4 r; x7 @ E1.2 NetworkX 工具包: z- B/ u3 A. F$ m
NetworkX 是基于 Python 语言的图论与复杂网络工具包,用于创建、操作和研究复杂网络的结构、动力学和功能。" T4 U0 s% N0 m r/ E2 W
' n% w) Y3 r' s: Y# kNetworkX 可以以标准和非标准的数据格式描述图与网络,生成图与网络,分析网络结构,构建网络模型,设计网络算法,绘制网络图形。
; w* c k: ~7 z4 J( a$ J2 v# ]# r, C: T; j3 H$ J( {
NetworkX 提供了图形的类、对象、图形生成器、网络生成器、绘图工具,内置了常用的图论和网络分析算法,可以进行图和网络的建模、分析和仿真。
) ]" c7 U% ~$ w5 S5 _% _" C+ l1 r% `3 q# Q0 Q5 I
NetworkX 的功能非常强大和庞杂,所涉及内容远远、远远地超出了数学建模的范围,甚至于很难进行系统的概括。本系列结合数学建模的应用需求,来介绍 NetworkX 图论与复杂网络工具包的基本功能和典型算法。) I: n" a7 c9 P
: d- D w, f: p* i
* H% t* K8 I) J- m2 p$ n
2、图、顶点和边的创建与基本操作
5 [; w# k: T1 G6 L图由顶点和连接顶点的边构成,但与顶点的位置、边的曲直长短无关。 Networkx 支持创建简单无向图、有向图和多重图;内置许多标准的图论算法,节点可为任意数据;支持任意的边值维度,功能丰富,简单易用。 2.1 图的基本概念
9 l$ z; e( @7 T* b' ^, O图(Graph):图是由若干顶点和连接顶点的边所构成关系结构。. v" R+ t4 D, L# ?2 }* l0 o
顶点(Node):图中的点称为顶点,也称节点。
; e- \/ ~+ y& C X( X边(Edge):顶点之间的连线,称为边。. f3 G' \9 F. m
平行边(Parallel edge):起点相同、终点也相同的两条边称为平行边。, T) Z; D: E2 i
循环(Cycle):起点和终点重合的边称为循环。: U+ W8 T, V2 X- `
有向图(Digraph):图中的每条边都带有方向,称为有向图。
+ N1 f3 O9 r5 i0 C/ z无向图(Undirected graph):图中的每条边都没有方向,称为无向图。' E8 t2 G& }4 o" c. ?
赋权图(Weighted graph):图中的每条边都有一个或多个对应的参数,称为赋权图。该参数称为这条边的权,权可以用来表示两点间的距离、时间、费用。
. @3 F3 A' ?! p( P- H& W度(Degree):与顶点相连的边的数量,称为该顶点的度。
1 c$ l4 e7 {( v4 p$ H) g# H" K
! h) e5 D/ l$ ^* q; \4 Z2.2 图、顶点和边的操作
, U* F* [2 B% k) u7 `Networkx很容易创建图、向图中添加顶点和边、从图中删除顶点和边,也可以查看、删除顶点和边的属性。
# _) w$ o$ r$ D u, P o) I" J
% h# z9 \) G6 z1 r7 Y0 C8 {; K2.2.1 图的创建Graph() 类、DiGraph() 类、MultiGraph() 类和 MultiDiGraph() 类分别用来创建:无向图、有向图、多图和有向多图。定义和例程如下:, B+ B0 o& S1 r2 T# I7 T
" d5 p/ P: d- q6 s1 I
class Graph(incoming_graph_data=None, **attr) H) d; D$ A: _: v' I7 D6 ~& c R9 S
import networkx as nx # 导入 NetworkX 工具包$ o7 F3 S8 h) S9 g: c: I& N
' Z$ X2 O0 q) A5 A/ w/ F* Z3 j# 创建 图% L% C1 R: `0 e. s$ `8 h
G1 = nx.Graph() # 创建:空的 无向图
0 i. V% F9 s0 ^- `% FG2 = nx.DiGraph() #创建:空的 有向图
( }. q/ @; N; U/ Q2 SG3 = nx.MultiGraph() #创建:空的 多图9 S9 I/ y9 Z% Q/ `- n+ Y: \6 y
G4 = nx.MultiDiGraph() #创建:空的 有向多图
. L% H+ |% P F/ j9 M( z! Y$ L( |$ u# B* P- |% k6 T' Q
( B& y* d4 J9 D/ g2.2.2 顶点的添加、删除和查看% |* V n8 \8 `8 o$ ?
图的每个顶点都有唯一的标签属性(label),可以用整数或字符类型表示,顶点还可以自定义任意属性。 顶点的常用操作:添加顶点,删除顶点,定义顶点属性,查看顶点和顶点属性。定义和例程如下: + Z$ i* M1 ~+ z6 K2 n% j2 J. S
Graph.add_node(node_for_adding, **attr)
& G/ n! Y Z6 J4 q& gGraph.add_nodes_from(nodes_for_adding, **attr)$ _9 R$ O7 k" D' H0 B+ S! P# l
Graph.remove_node(n)9 A, {) j$ N# A- j* Y
Graph.remove_nodes_from(nodes)8 Q$ ~ }; L1 `
7 q+ [* G- I$ b, g$ c4 g" H
# 顶点(node)的操作
+ u5 z8 M* | u9 ^1 U; w6 d# 向图中添加顶点7 ~; f- }# W0 W9 H1 Y3 ]
G1.add_node(1) # 向 G1 添加顶点 1
) r2 N/ n$ n. ~; _- d: S! @G1.add_node(1, name='n1', weight=1.0) # 添加顶点 1,定义 name, weight 属性6 ~: f' O. `9 b) J& Y) }, t
G1.add_node(2, date='May-16') # 添加顶点 2,定义 time 属性
' b9 J, \/ i) o- o+ R+ GG1.add_nodes_from([3, 0, 6], dist=1) # 添加多个顶点,并定义属性
/ P& r/ w V8 _ {: @G1.add_nodes_from(range(10, 15)) # 向图 G1 添加顶点 10~14
; f: [: z% X0 a2 `" V9 M' z9 L1 D) k- S5 g5 O% H
# 查看顶点和顶点属性
9 j6 F* z" o- A" kprint(G1.nodes()) # 查看顶点列表
! c- m4 I- i1 W7 N3 o! d# [1, 2, 3, 0, 6, 10, 11, 12, 13, 14]
4 c1 `: u$ y. ]( H4 Nprint(G1._node) # 查看顶点属性+ U0 E+ x! u' U! u- H$ e
# {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 r& g, u0 v T( U/ e: Q4 U
j% D' l1 [ ]% f# 从图中删除顶点
' H" ?& a) S1 N! kG1.remove_node(1) # 删除顶点
_0 ?6 Z% r7 O7 P7 P8 LG1.remove_nodes_from([1, 11, 13, 14]) # 通过顶点标签的 list 删除多个顶点
: s8 q0 K+ w4 f2 {print(G1.nodes()) # 查看顶点
+ _4 |3 R8 T( j: q: }3 k. D8 t# [2, 3, 0, 6, 10, 12] # 顶点列表
& i- U# l) M+ }* J7 G2.2.3 边的添加、删除和查看边是两个顶点之间的连接,在 NetworkX 中 边是由对应顶点的名字的元组组成 e=(node1,node2)。边可以设置权重、关系等属性。 边的常用操作:添加边,删除边,定义边的属性,查看边和边的属性。向图中添加边时,如果边的顶点是图中不存在的,则自动向图中添加该顶点。 Graph.add_edge(u_of_edge, v_of_edge, **attr)
7 w! A. @( Z" ^! N VGraph.add_edges_from(ebunch_to_add, **attr); u5 E1 D! I2 t) I. h9 ]
Graph.add_weighted_edges_from(ebunch_to_add, weight=‘weight’, **attr)2 R7 b v. ~# u; D
0 _! a" ]+ m, F4 N# 边(edge)的操作
# R+ @7 \0 J& `% u# 向图中添加边+ k, u+ d9 \: F4 Q
G1.add_edge(1,5) # 向 G1 添加边,并自动添加图中没有的顶点8 V2 D ?/ a8 _- D% l6 ^/ m
G1.add_edge(0,10, weight=2.7) # 向 G1 添加边,并设置边的属性 x" J* v8 ^+ O6 L* _0 k1 ~" z
G1.add_edges_from([(1,2,{'weight':0}), (2,3,{'color':'blue'})]) # 向图中添加边,并设置属性
* j! n H: C% `G1.add_edges_from([(3,6),(1,2),(6,7),(5,10),(0,1)]) # 向图中添加多条边
7 G6 n% o0 X. [% K6 \$ c# |G1.add_weighted_edges_from([(1,2,3.6),[6,12,0.5]]) # 向图中添加多条赋权边: (node1,node2,weight)+ t6 R9 C5 _! J: i) B
print(G1.nodes()) # 查看顶点
! ^* F* o" J; }% H# ?# [2, 3, 0, 6, 10, 12, 1, 5, 7] # 自动添加了图中没有的顶点 P3 l; |/ e9 M I1 H
. @2 L3 z, c3 ^& h9 i, K2 @1 T. [2 T
# 从图中删除边
# I J# F' L8 [ n0 R) K* BG1.remove_edge(0,1) # 从图中删除边 0-10 f, r0 B- @+ {9 P* {& ^! g( h
G1.remove_edges_from([(2,3),(1,5),(6,7)]) # 从图中删除多条边
: x2 D; x9 Q. ]3 c; Z( y3 Q w! ]9 j) ~
# 查看 边和边的属性
! W& c0 {- @( u& g- f$ S$ j* |print(G1.edges) # 查看所有的边1 W% B$ \% T& E/ w; x
[(2, 1), (3, 6), (0, 10), (6, 12), (10, 5)]
8 M9 q' o4 f# y7 U1 dprint(G1.get_edge_data(1,2)) # 查看指定边的属性
7 n3 ~. U$ |5 h; P ]4 b+ a# {'weight': 3.6}$ D6 u( j% P5 ~5 s$ Y; U) s$ y
print(G1[1][2]) # 查看指定边的属性
6 d+ W; q3 w0 ?" W+ s6 Y/ i# {'weight': 3.6}
. }. p: S' V+ j2 Vprint(G1.edges(data=True)) # 查看所有边的属性
; F0 I2 {& S5 @1 X# [(2, 1, {'weight': 3.6}), (3, 6, {}), (0, 10, {'weight': 2.7}), (6, 12, {'weight': 0.5}), (10, 5, {})]
1 ^' t- F) L ~: X" x+ A, P, q- O2 ^4 J7 O( O/ D
2.2.4 查看图、顶点和边的信息4 X. o; z1 w# Y3 Q: Z4 Q; w$ v
' }$ Z& m7 v" \0 @4 L9 q# 查看图、顶点和边的信息9 D! @7 o0 Z' q5 O; |0 a
print(G1.nodes) # 返回所有的顶点 [node1,...]: o. z( l/ w: w8 |) Z) N5 T/ ~
# [2, 3, 0, 6, 10, 12, 1, 5, 7]8 k2 n7 R3 f, W/ b2 W
print(G1.edges) # 返回所有的边 [(node1,node2),...]
7 e; u R% H! k4 ]# [(2, 1), (3, 6), (0, 10), (6, 12), (10, 5)]
5 u% Y/ n; ^4 P0 N. ^print(G1.degree) # 返回各顶点的度 [(node1,degree1),...]
' {9 v; J3 k9 n% _4 \) m# [(2, 1), (3, 1), (0, 1), (6, 2), (10, 2), (12, 1), (1, 1), (5, 1), (7, 0)]
! y! [1 P) z% G; D' Y* G' Y1 mprint(G1.number_of_nodes()) # 返回顶点的数量( N" k: K* @$ t& r: n
# 9
# {4 v8 g" f0 l) y! K& `9 zprint(G1.number_of_edges()) # 返回边的数量
/ V/ m% I) Z9 z6 N0 P# 5
" U0 t" X6 g& x4 I7 I1 t( Kprint(G1[10]) # 返回与指定顶点相邻的所有顶点的属性/ O6 C$ F6 O0 a1 l9 y# A7 F
# {0: {'weight': 2.7}, 5: {}}
$ e: ?' z6 ~. h' v8 \print(G1.adj[10]) # 返回与指定顶点相邻的所有顶点的属性
; @* _% `- p" _- m) S1 t+ ]. k! m, L# {0: {'weight': 2.7}, 5: {}} F$ u8 \" x ?" p
print(G1[1][2]) # 返回指定边的属性
2 K* j0 P1 N) G/ n; B( }, y# j# {'weight': 3.6}$ X* E! b8 f' G& R2 M1 O8 }
print(G1.adj[1][2]) # 返回指定边的属性0 R, E2 [0 m" I# \1 n
# {'weight': 3.6}5 @9 o( k0 P2 H" Q& u
print(G1.degree(10)) # 返回指定顶点的度. q( w7 y0 R% O3 `1 k
# 2
& X: o. S+ y6 s, G- R
% K5 h. I3 H7 q' w+ c3 U4 G! [% `print('nx.info:',nx.info(G1)) # 返回图的基本信息' Y1 o& U# f6 [; ^2 M6 I
print('nx.degree:',nx.degree(G1)) # 返回图中各顶点的度2 _$ W, B+ s; a N
print('nx.density:',nx.degree_histogram(G1)) # 返回图中度的分布
# S$ R; k* C2 D) {print('nx.pagerank:',nx.pagerank(G1)) # 返回图中各顶点的频率分布' Q2 w6 ]% ]* @4 O2 H
! H7 r- {2 k! u1 v6 C l
* r, n- \( N8 j% Y( Q' C- A) \# N7 q3 _$ }
6 h9 m T! i1 }, u2 {
5 l! h1 q/ |: T' V2.3 图的属性和方法图的方法
) r* Y& I0 ^/ X. A! _2 w
: d `% g8 z' w* j6 }! Z4 j0 U方法 说明6 U% t8 v( J9 o: T2 b. _/ S
G.has_node(n) 当图 G 中包括顶点 n 时返回 True
$ F4 M7 e1 U9 H% R6 i! x1 RG.has_edge(u, v) 当图 G 中包括边 (u,v) 时返回 True& d0 N0 u7 v1 M
G.number_of_nodes() 返回 图 G 中的顶点的数量
* Z" q+ Y8 B7 FG.number_of_edges() 返回 图 G 中的边的数量- J/ X) a* J1 t+ l
G.number_of_selfloops() 返回 图 G 中的自循环边的数量" n& S- g3 A7 G0 k
G.degree([nbunch, weight]) 返回 图 G 中的全部顶点或指定顶点的度- J( f, h& V4 |$ q& @2 ~) S! a
G.selfloop_edges([data, default]) 返回 图 G 中的全部的自循环边4 Q/ z* O5 @2 x5 L, z) Y* ?9 ^0 `
G.subgraph([nodes]) 从图 G1中抽取顶点[nodes]及对应边构成的子图
+ s5 V/ G/ @. L' e- p9 ~9 yunion(G1,G2) 合并图 G1、G2
, i h$ g& k- L/ G; Q0 Anx.info(G) 返回图的基本信息
' |3 q7 `. h# _nx.degree(G) 返回图中各顶点的度" l* {4 l/ {, i5 H" l/ F
nx.degree_histogram(G) 返回图中度的分布
% W) E7 b8 H# _5 P. n; v2 H7 ?nx.pagerank(G) 返回图中各顶点的频率分布
. j! L8 h( }8 w9 {+ a: T& gnx.add_star(G,[nodes],**attr) 向图 G 添加星形网络0 g0 `* u0 o6 D/ k
nx.add_path(G,[nodes],**attr) 向图 G 添加一条路径
; a6 L4 C E5 B8 B! e7 Tnx.add_cycle(G,[nodes],**attr) 向图 G 添加闭合路径7 C8 g# z+ x% q% P0 b+ q+ w! f/ l
1 r. R; h$ @7 W. T+ v. U
0 z9 U9 v( ]3 x2 d; q" l) [. y例程:
3 Z4 Y+ J% y* B4 mG1.clear() # 清空图G1
! Q4 k5 H% c7 v" g3 wnx.add_star(G1, [1, 2, 3, 4, 5], weight=1) # 添加星形网络:以第一个顶点为中心! x! z* s4 D% j0 @. C3 v
# [(1, 2), (1, 3), (1, 4), (1, 5)]
& R' d* D1 [& W8 q$ P C5 [; rnx.add_path(G1, [5, 6, 8, 9, 10], weight=2) # 添加路径:顺序连接 n个节点的 n-1条边
* |8 J9 w# S! _# j; C9 p0 ^4 Z# [(5, 6), (6, 8), (8, 9), (9, 10)]' |) Z5 S$ l2 E
nx.add_cycle(G1, [7, 8, 9, 10, 12], weight=3) # 添加闭合回路:循环连接 n个节点的 n 条边 e+ r8 E `; U7 B4 n; q
# [(7, 8), (7, 12), (8, 9), (9, 10), (10, 12)]; F* K/ w, |5 _1 J6 H+ ]- L
print(G1.nodes) # 返回所有的顶点 [node1,...]) `: z" Y1 [! h. V$ [- j
nx.draw_networkx(G1)
4 I6 Z5 d& p9 y# B# E" Bplt.show()7 C/ I1 l6 `& v4 I! d8 z! u
8 x1 M; ?$ v* @8 q! y; C! l' D
G2 = G1.subgraph([1, 2, 3, 8, 9, 10])
8 b2 l6 X% p, [& J8 k; UG3 = G1.subgraph([4, 5, 6, 7])
" F* {/ f/ U: O+ b1 q& M8 ^G = nx.union(G2, G3)
2 g5 f! F0 R% yprint(G.nodes) # 返回所有的顶点 [node1,...]
% F# e4 j) u3 q7 U$ H1 x+ U, X, b# [1, 2, 3, 8, 9, 10, 4, 5, 6, 7]( L* d& }/ Y, {+ k& f" b
& n" a( S H- \" a% Q6 U& |+ J
) L' G- f' [3 G |3、图的绘制与分析3.1 图的绘制
( l- r; p1 g- n1 I$ h# L' p可视化是图论和网络问题中很重要的内容。NetworkX 在 Matplotlib、Graphviz 等图形工具包的基础上,提供了丰富的绘图功能。2 z9 u7 x7 T9 h$ o, \- E
2 I6 Y; ~% U `9 o' Q1 p4 Y本系列拟对图和网络的可视化作一个专题,在此只简单介绍基于 Matplotlib 的基本绘图函数。基本绘图函数使用字典提供的位置将节点放置在散点图上,或者使用布局函数计算位置。) E/ B1 M! L- I- j$ E f$ G. i, N
8 D" R+ H. w, @! `方法 说明. L% b& d$ O# }5 v( {" k
draw(G[,pos,ax]) 基于 Matplotlib 绘制 图 G
# O6 t. j/ K3 A* b! zdraw_networkx(G[, pos, arrows, with_labels]) 基于 Matplotlib 绘制 图 G7 C- [) a! H/ X% _- v. `
draw_networkx_nodes(G, pos[, nodelist, . . . ]) 绘制图 G 的顶点
( H9 ? { z3 o6 B) X( ~draw_networkx_edges(G, pos[, edgelist, . . . ]) 绘制图 G 的边- A2 s6 n3 S# i
draw_networkx_labels(G, pos[, labels, . . . ]) 绘制顶点的标签
0 W0 E) d% x9 ]: x$ ?8 idraw_networkx_edge_labels(G, pos[, . . . ]) 绘制边的标签3 { a) _8 J( Y& D
1 r1 M7 D3 l- n4 p1 E5 T; r
0 H2 |; e/ o9 y' F
其中,nx.draw() 和 nx.draw_networkx() 是最基本的绘图函数,并可以通过自定义函数属性或其它绘图函数设置不同的绘图要求。
6 Q# g2 U, i' p! g$ x! y( z* gdraw(G, pos=None, ax=None, **kwds) draw_networkx(G, pos=None, arrows=True, with_labels=True, **kwds) Q a. E) n* B7 w0 q
常用的属性定义如下:, S' Q) x: h/ @. }: V
) Z& b( @6 a ]# B8 I) W8 P6 M/ k( q‘node_size’:指定节点的尺寸大小,默认3009 S. m& L- T( v; V
‘node_color’:指定节点的颜色,默认红色
! f; t: x) H/ ~$ _‘node_shape’:节点的形状,默认圆形, Z% ~; B; q4 Q
'‘alpha’:透明度,默认1.0,不透明
& B% G- `- ^, S6 a‘width’:边的宽度,默认1.0
" o4 a1 w7 T5 a/ K; Q# {+ e% d‘edge_color’:边的颜色,默认黑色. R$ l6 U# K) K8 _: T- U
‘style’:边的样式,可选 ‘solid’、‘dashed’、‘dotted’、‘dashdot’
Y) K( r1 g) l: m2 V: D( [9 X‘with_labels’:节点是否带标签,默认True% L% R* R8 k% I1 K9 b7 @* D+ [3 j5 h9 B
‘font_size’:节点标签字体大小,默认12; E' D7 y! ?5 ] m1 n& o1 l
‘font_color’:节点标签字体颜色,默认黑色
5 q3 j1 T# w; e! H' d4 j1 l+ W
7 P! B* ~6 _2 U6 \" q0 d![]()
) U ^- F/ ~; E5 Q6 ^4 l3.2 图的分析NetwotkX 提供了图论函数对图的结构进行分析
. a; ?2 k% A: Y+ `& T子图 F6 B( q* _, \/ x- j: |% x# B3 |
- 子图是指顶点和边都分别是图 G 的顶点的子集和边的子集的图。
- subgraph()方法,按顶点从图 G 中抽出子图。例程如前。 B/ K% L8 Q) e& l% g
连通子图% a8 O9 i, `& E/ ^+ K
, I8 E, y5 w* C3 |: \) w8 N% d- 如果图 G 中的任意两点间相互连通,则 G 是连通图。
- [color=rgba(0, 0, 0, 0.749019607843137)]connected_components()方法,返回连通子图的集合。/ [5 B# X& ?( u% H" T2 r+ e8 n
[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}]
7 E# n4 _: C) s0 E% o
8 [) d! j5 ]5 H) N
+ J+ s8 A" |7 r: w% K" Q3 x# D, n: O5 @' ]4 O
$ P. n& U+ [/ t+ k1 o; ?. a" T8 E |