Python小白的数学建模课-图论的基本概念
& f# p, G! c0 o0 m- ]1 f+ t- Y1 Z# f# F6 g5 e/ |' M
- 图论中所说的图,不是图形图像或地图,而是指由顶点和边所构成的图形结构。
- 图论不仅与拓扑学、计算机数据结构和算法密切相关,而且正在成为机器学习的关键技术。
- 本系列结合数学建模的应用需求,来介绍 NetworkX 图论与复杂网络工具包的基本功能和典型算法。7 w0 I/ u+ X/ w; }9 I" F: v- |0 {7 h
3 G' N' P0 V V' Q1. 图论1.1 图论是什么( r }$ f& I7 \* ?4 e
图论〔Graph Theory〕以图为研究对象,是离散数学的重要内容。图论不仅与拓扑学、计算机数据结构和算法密切相关,而且正在成为机器学习的关键技术。
: X% o" K, d. c9 T7 Q9 e
3 m, S* ~. l, D7 l& k9 v图论中所说的图,不是指图形图像(image)或地图(map),而是指由顶点(vertex)和连接顶点的边(edge)所构成的关系结构。& O* L3 q/ R2 T7 @+ [. g
" z. ] C8 F4 E/ U
图提供了一种处理关系和交互等抽象概念的更好的方法,它还提供了直观的视觉方式来思考这些概念。
$ E6 d% K: ]- Q1 \5 y; _) H: s% k7 o
1.2 NetworkX 工具包+ _* L$ A- a5 L" V
NetworkX 是基于 Python 语言的图论与复杂网络工具包,用于创建、操作和研究复杂网络的结构、动力学和功能。) k* V3 t- w `8 \2 I* O
" C, G! |0 x) o$ Q. H' T# `0 z
NetworkX 可以以标准和非标准的数据格式描述图与网络,生成图与网络,分析网络结构,构建网络模型,设计网络算法,绘制网络图形。* t7 D! i9 H( K! C# O4 r
- m7 M% ]1 g/ N' J. RNetworkX 提供了图形的类、对象、图形生成器、网络生成器、绘图工具,内置了常用的图论和网络分析算法,可以进行图和网络的建模、分析和仿真。
3 I& L/ W, }9 B% w9 V% G; l" e
+ s, w1 J* z0 _! k8 ]) Q: tNetworkX 的功能非常强大和庞杂,所涉及内容远远、远远地超出了数学建模的范围,甚至于很难进行系统的概括。本系列结合数学建模的应用需求,来介绍 NetworkX 图论与复杂网络工具包的基本功能和典型算法。
. z8 }! c! F3 A# h# V0 @
/ D! L0 C; T+ a' U( p: {' S . B; d* @9 B8 M b& U) m4 l
2、图、顶点和边的创建与基本操作! B/ J/ ^7 W# d
图由顶点和连接顶点的边构成,但与顶点的位置、边的曲直长短无关。 Networkx 支持创建简单无向图、有向图和多重图;内置许多标准的图论算法,节点可为任意数据;支持任意的边值维度,功能丰富,简单易用。 2.1 图的基本概念* G7 `2 n# z$ g: W8 {
图(Graph):图是由若干顶点和连接顶点的边所构成关系结构。3 t1 o4 I4 o6 D( G: n& Q/ Q% s6 q
顶点(Node):图中的点称为顶点,也称节点。: U9 d8 P- t- w; |& X' G
边(Edge):顶点之间的连线,称为边。
: H6 q; C$ L- `! m, U; E平行边(Parallel edge):起点相同、终点也相同的两条边称为平行边。 a+ x( U4 W% x( h! e" c
循环(Cycle):起点和终点重合的边称为循环。$ P2 l7 d I9 d, x
有向图(Digraph):图中的每条边都带有方向,称为有向图。* ?# {. G3 m; E) t
无向图(Undirected graph):图中的每条边都没有方向,称为无向图。
" j- C/ D# D: j$ K9 }9 X赋权图(Weighted graph):图中的每条边都有一个或多个对应的参数,称为赋权图。该参数称为这条边的权,权可以用来表示两点间的距离、时间、费用。! Z+ U0 f$ V3 H! X# S1 q- C3 B/ [
度(Degree):与顶点相连的边的数量,称为该顶点的度。' j+ E$ ?* u6 ?4 @6 r* |( G
1 M' b6 \3 \0 \% ^/ N5 X4 Y
2.2 图、顶点和边的操作+ ]/ `" P) P/ O! p, X' i; D
Networkx很容易创建图、向图中添加顶点和边、从图中删除顶点和边,也可以查看、删除顶点和边的属性。% }+ E" B' a5 ^8 T( R5 b. Z9 P
$ y* J5 \& i1 x2.2.1 图的创建Graph() 类、DiGraph() 类、MultiGraph() 类和 MultiDiGraph() 类分别用来创建:无向图、有向图、多图和有向多图。定义和例程如下:! C6 d) R/ W9 m2 a" O( j: j
7 V q. `5 W9 D6 I/ cclass Graph(incoming_graph_data=None, **attr)
M, \7 d, f7 yimport networkx as nx # 导入 NetworkX 工具包
5 F! [ Z b& j8 H2 A) I$ r" F" W% ^" c8 Z
# 创建 图+ m( l, j9 [/ f9 J* S- }
G1 = nx.Graph() # 创建:空的 无向图
- C, `; L4 F" q% i: bG2 = nx.DiGraph() #创建:空的 有向图1 {! ^) ?! l( _ l6 X
G3 = nx.MultiGraph() #创建:空的 多图
# w" w4 o0 d/ m1 V, J: p* N% jG4 = nx.MultiDiGraph() #创建:空的 有向多图. O q& j1 k9 }7 C; }8 }6 z5 l
8 F: d6 I# }' Z/ g( D
- D2 S# d2 U+ A$ m* f, @2.2.2 顶点的添加、删除和查看4 r3 |' k& w7 k% @3 r6 M: z1 u9 F
图的每个顶点都有唯一的标签属性(label),可以用整数或字符类型表示,顶点还可以自定义任意属性。 顶点的常用操作:添加顶点,删除顶点,定义顶点属性,查看顶点和顶点属性。定义和例程如下:
7 ?0 J' ]8 \/ n. r9 X% eGraph.add_node(node_for_adding, **attr)2 C9 d; E1 m- S; R/ O5 [* g/ a
Graph.add_nodes_from(nodes_for_adding, **attr)! ]' v) t+ x0 E( ~3 A$ k
Graph.remove_node(n)
. C6 O6 P9 n r* b6 FGraph.remove_nodes_from(nodes)' d) B B7 t! b: x/ x
6 J/ {: d" Y. n* a; K; A: G# 顶点(node)的操作
. y; z$ a3 e# b m4 F# 向图中添加顶点
- H& I( Z" c) m% s7 Q; \' ]( z% vG1.add_node(1) # 向 G1 添加顶点 19 ^8 n. S! u0 m6 m# K" o
G1.add_node(1, name='n1', weight=1.0) # 添加顶点 1,定义 name, weight 属性% [9 J: u/ _- b% S# }
G1.add_node(2, date='May-16') # 添加顶点 2,定义 time 属性
" E2 F% L2 ^8 S. _4 PG1.add_nodes_from([3, 0, 6], dist=1) # 添加多个顶点,并定义属性6 r1 V; j0 [# g7 _ u
G1.add_nodes_from(range(10, 15)) # 向图 G1 添加顶点 10~14
0 b2 O' f4 O; |* i2 |; y+ P3 f9 n- R/ i5 H/ F
# 查看顶点和顶点属性
/ D. Y' ?/ S, s( t0 nprint(G1.nodes()) # 查看顶点列表
/ C' E* P5 `/ X; B1 L5 d, a: I- H) A3 V# [1, 2, 3, 0, 6, 10, 11, 12, 13, 14]7 ^0 B* I' D+ L. Q2 X# H
print(G1._node) # 查看顶点属性
+ Q6 e$ S J8 S8 z0 a6 r9 \) 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: {}}9 w( U/ [! J( F; v$ q
( t8 P4 t- L, ` i# i9 o
# 从图中删除顶点
8 D( G0 M; i" |7 y/ z$ ^5 [G1.remove_node(1) # 删除顶点
7 d, @$ J4 A2 X1 f9 N- @* _' HG1.remove_nodes_from([1, 11, 13, 14]) # 通过顶点标签的 list 删除多个顶点/ R0 Q, u: M$ r" V
print(G1.nodes()) # 查看顶点
3 ^3 Z' j9 j( r9 S4 d+ O: O3 J: @# [2, 3, 0, 6, 10, 12] # 顶点列表
) [' x) g9 U4 k0 a0 G2.2.3 边的添加、删除和查看边是两个顶点之间的连接,在 NetworkX 中 边是由对应顶点的名字的元组组成 e=(node1,node2)。边可以设置权重、关系等属性。 边的常用操作:添加边,删除边,定义边的属性,查看边和边的属性。向图中添加边时,如果边的顶点是图中不存在的,则自动向图中添加该顶点。 Graph.add_edge(u_of_edge, v_of_edge, **attr)5 v3 |# L% L% t" }4 v
Graph.add_edges_from(ebunch_to_add, **attr)
/ o' U2 R8 U. R6 A. G5 p6 nGraph.add_weighted_edges_from(ebunch_to_add, weight=‘weight’, **attr)
5 L8 S6 a" S" T5 p( C2 T5 C' h
9 E( X J6 t# n5 G# 边(edge)的操作. r) x# R/ F5 d9 O( [' ^; P
# 向图中添加边! z' ]) r/ Z$ J( ^- n
G1.add_edge(1,5) # 向 G1 添加边,并自动添加图中没有的顶点
( [+ B1 ~3 V+ ^& Y( gG1.add_edge(0,10, weight=2.7) # 向 G1 添加边,并设置边的属性
, R" g. v6 ^+ i, @# j. ]G1.add_edges_from([(1,2,{'weight':0}), (2,3,{'color':'blue'})]) # 向图中添加边,并设置属性$ O+ _) m9 z6 H# S7 Q+ S
G1.add_edges_from([(3,6),(1,2),(6,7),(5,10),(0,1)]) # 向图中添加多条边$ z- L9 H5 q; x x ]! e
G1.add_weighted_edges_from([(1,2,3.6),[6,12,0.5]]) # 向图中添加多条赋权边: (node1,node2,weight)( t+ w2 [5 a# Z) c* U6 z
print(G1.nodes()) # 查看顶点
, F6 n* v+ d8 F' y# [2, 3, 0, 6, 10, 12, 1, 5, 7] # 自动添加了图中没有的顶点' t" {# L2 ^* @# h, B
; g8 Z6 `- z6 u, H# 从图中删除边9 ]* w1 y: T: ?$ k3 j% z% c5 z6 B* w
G1.remove_edge(0,1) # 从图中删除边 0-1
3 A" }: X2 Y! `G1.remove_edges_from([(2,3),(1,5),(6,7)]) # 从图中删除多条边
$ f7 |6 w9 x8 I5 K* T- v
3 D. b* V+ `% g# `8 K6 J# 查看 边和边的属性
( r/ U2 }$ i6 L' n Z5 Fprint(G1.edges) # 查看所有的边% F5 A: v, j6 A' [: Q; q& R
[(2, 1), (3, 6), (0, 10), (6, 12), (10, 5)]6 r+ A( O( ~4 q& Z
print(G1.get_edge_data(1,2)) # 查看指定边的属性5 H9 k& L! S8 g) N: V5 ~
# {'weight': 3.6}
% C" a0 H/ _1 E* ^& Wprint(G1[1][2]) # 查看指定边的属性
' _6 m) |; z! k. {$ b) l# {'weight': 3.6}! z; o0 [8 C6 ~+ t6 f6 P0 i$ [! w
print(G1.edges(data=True)) # 查看所有边的属性# J$ b* g; ~) Z2 U: }% f6 \1 D& a
# [(2, 1, {'weight': 3.6}), (3, 6, {}), (0, 10, {'weight': 2.7}), (6, 12, {'weight': 0.5}), (10, 5, {})]
. A6 I# d/ J9 n4 ~
d6 c$ _/ S8 ~- h4 R& \7 g2.2.4 查看图、顶点和边的信息
- i) x8 p/ g+ Y* j* q6 X0 I$ ?* p$ t' E$ i, `
# 查看图、顶点和边的信息
7 W& _ ~: y b* Z$ bprint(G1.nodes) # 返回所有的顶点 [node1,...]
) \8 @* c3 U" l a# [2, 3, 0, 6, 10, 12, 1, 5, 7]" _. w* \( `6 z1 F @, ? b+ c
print(G1.edges) # 返回所有的边 [(node1,node2),...]* V! k* X$ ~% i& g2 e
# [(2, 1), (3, 6), (0, 10), (6, 12), (10, 5)]
3 @# y. M' g G' n! H# \print(G1.degree) # 返回各顶点的度 [(node1,degree1),...]
3 x2 `* w( N% u. W8 I; h) {# [(2, 1), (3, 1), (0, 1), (6, 2), (10, 2), (12, 1), (1, 1), (5, 1), (7, 0)]
% I$ H7 Q0 H" X6 Uprint(G1.number_of_nodes()) # 返回顶点的数量
% J& M+ |/ H1 T# 9' k4 h0 ^; [( B
print(G1.number_of_edges()) # 返回边的数量/ w$ z1 D( }1 K. o; {
# 5
# {( l. b) u4 z; uprint(G1[10]) # 返回与指定顶点相邻的所有顶点的属性
. p6 j; I7 A G3 c# {0: {'weight': 2.7}, 5: {}}
: `) R0 x* i- B A0 L B" b0 Nprint(G1.adj[10]) # 返回与指定顶点相邻的所有顶点的属性# y( }) @( ]5 a/ u8 w6 R8 h1 c( I& m% ]
# {0: {'weight': 2.7}, 5: {}}; }# {7 @, Q0 g$ w$ P6 |
print(G1[1][2]) # 返回指定边的属性% J! F8 W3 `: w& b
# {'weight': 3.6}
' L9 @% {8 k& o4 S6 m' Gprint(G1.adj[1][2]) # 返回指定边的属性* i: E# Q" |: l) d& \' |8 E
# {'weight': 3.6}
/ P4 l4 J- D& @; xprint(G1.degree(10)) # 返回指定顶点的度
: ~2 T4 f* N# g8 ~3 z+ x# 2
) I6 \3 i, I! \/ U' F* R) B9 z
; B* E! Q# r5 y8 d3 k2 U, }print('nx.info:',nx.info(G1)) # 返回图的基本信息/ b" x( I4 l! T; R" K0 G# O
print('nx.degree:',nx.degree(G1)) # 返回图中各顶点的度
" c6 T4 G+ O3 V; a% K: Dprint('nx.density:',nx.degree_histogram(G1)) # 返回图中度的分布9 f. ~9 ?$ t# e$ f! _( p
print('nx.pagerank:',nx.pagerank(G1)) # 返回图中各顶点的频率分布/ q5 B: Q# f% V. o$ B7 c% T: v
; \, m( m6 I b9 Y
7 Z7 _9 P3 m; R N5 x
( t8 E, m# Y9 ^1 h9 k( [5 }
- G# ]6 [. q; k R, V! k4 h
: S$ Y3 S9 [/ O/ _4 D4 Z2.3 图的属性和方法图的方法1 s8 U- P% \4 z# E
- A, d6 @. c3 J) ?, V: B" \
方法 说明
}! [6 d: @4 t9 w. bG.has_node(n) 当图 G 中包括顶点 n 时返回 True
' Y/ p, ^' Z( I9 PG.has_edge(u, v) 当图 G 中包括边 (u,v) 时返回 True/ q* C! |& X. l0 l$ ]1 V" i% V8 H
G.number_of_nodes() 返回 图 G 中的顶点的数量1 _4 I3 I) Y$ e; o+ V; ]+ @
G.number_of_edges() 返回 图 G 中的边的数量
0 N- m. \+ m. ]8 p! c2 YG.number_of_selfloops() 返回 图 G 中的自循环边的数量
$ D( N7 O3 [5 n' ~2 R1 sG.degree([nbunch, weight]) 返回 图 G 中的全部顶点或指定顶点的度* v- }5 P# I+ A
G.selfloop_edges([data, default]) 返回 图 G 中的全部的自循环边
# }- f1 K% D0 a4 z7 r' X8 e/ L6 NG.subgraph([nodes]) 从图 G1中抽取顶点[nodes]及对应边构成的子图
' A" O: C, R$ ]) ~7 G: c4 H9 Funion(G1,G2) 合并图 G1、G29 p% |) o3 ~0 S1 b4 m
nx.info(G) 返回图的基本信息
3 f/ _& F6 e, S6 [7 ^! E$ k+ dnx.degree(G) 返回图中各顶点的度8 y- t* L( B- p& @ B: D8 _
nx.degree_histogram(G) 返回图中度的分布 b: d* x& M" M* i' j3 R* a! z$ \
nx.pagerank(G) 返回图中各顶点的频率分布. v% h7 `1 m$ \& o7 W
nx.add_star(G,[nodes],**attr) 向图 G 添加星形网络# S6 V" {# a" P: P
nx.add_path(G,[nodes],**attr) 向图 G 添加一条路径
4 z; T0 Y6 r* Z- L: ~' Nnx.add_cycle(G,[nodes],**attr) 向图 G 添加闭合路径( x. I- p7 o* Z9 E: \9 d X
2 x- E5 {+ f; f' H+ \1 ]
' m* {5 f+ I# A( Z& Y- |例程:* l$ ~9 e3 ]; W# Z) o
G1.clear() # 清空图G1) r3 f, K) i" W, w) d4 c6 P
nx.add_star(G1, [1, 2, 3, 4, 5], weight=1) # 添加星形网络:以第一个顶点为中心
- k! j7 s( o2 ?: X' L# [(1, 2), (1, 3), (1, 4), (1, 5)]
+ f# ]# A2 v: t- }; enx.add_path(G1, [5, 6, 8, 9, 10], weight=2) # 添加路径:顺序连接 n个节点的 n-1条边1 p! A8 t% s; ^, Q5 I
# [(5, 6), (6, 8), (8, 9), (9, 10)]- Z+ A4 F4 g5 b; d& M7 P
nx.add_cycle(G1, [7, 8, 9, 10, 12], weight=3) # 添加闭合回路:循环连接 n个节点的 n 条边! m6 O/ F3 O S2 X) I
# [(7, 8), (7, 12), (8, 9), (9, 10), (10, 12)]2 I w) a# j0 n( d$ m, ^
print(G1.nodes) # 返回所有的顶点 [node1,...]8 _& ?6 B1 V6 ?2 x
nx.draw_networkx(G1)
# Z7 ?: O0 d' _! k3 lplt.show()
! w: X* | M q$ l2 e* l6 V
1 U# Y% Y( ^) ^* Y7 l9 VG2 = G1.subgraph([1, 2, 3, 8, 9, 10]). c: H6 i1 [# J* {: B z
G3 = G1.subgraph([4, 5, 6, 7])( s$ g* n; p( i3 c: V
G = nx.union(G2, G3)- c. a, Y2 a$ i
print(G.nodes) # 返回所有的顶点 [node1,...]/ W2 a( T/ e2 _. O
# [1, 2, 3, 8, 9, 10, 4, 5, 6, 7]
0 m* [5 P$ t$ {0 @$ j" D( m9 S6 i7 Y
1 @3 k# f, A' X7 n' K6 R0 L2 r3、图的绘制与分析3.1 图的绘制- }( {2 V8 c. Y0 \
可视化是图论和网络问题中很重要的内容。NetworkX 在 Matplotlib、Graphviz 等图形工具包的基础上,提供了丰富的绘图功能。
% N7 m$ k* [3 [1 b! g
& e6 K9 Z( b9 D本系列拟对图和网络的可视化作一个专题,在此只简单介绍基于 Matplotlib 的基本绘图函数。基本绘图函数使用字典提供的位置将节点放置在散点图上,或者使用布局函数计算位置。; I4 w8 S: p+ t; D8 q
# l1 R7 T8 U5 f2 h" H$ l
方法 说明
- d3 F2 N4 H; A( `" sdraw(G[,pos,ax]) 基于 Matplotlib 绘制 图 G* c q+ p, D& X/ t x- P9 q
draw_networkx(G[, pos, arrows, with_labels]) 基于 Matplotlib 绘制 图 G( L7 f0 Q# a! k" ]) Q, d. K
draw_networkx_nodes(G, pos[, nodelist, . . . ]) 绘制图 G 的顶点
/ j: U6 }) E( b7 v6 S0 o pdraw_networkx_edges(G, pos[, edgelist, . . . ]) 绘制图 G 的边5 m3 c$ f2 q6 _; J. ^( _$ M2 }
draw_networkx_labels(G, pos[, labels, . . . ]) 绘制顶点的标签
( e! G# S7 X4 |/ sdraw_networkx_edge_labels(G, pos[, . . . ]) 绘制边的标签
7 H! Q! S9 s' Y1 Z1 w6 T4 _8 o+ k) l u7 f3 p. i o/ l) A
8 ?. L2 v2 w5 c) _) s/ w# o
其中,nx.draw() 和 nx.draw_networkx() 是最基本的绘图函数,并可以通过自定义函数属性或其它绘图函数设置不同的绘图要求。
n2 M* t3 h U) I. h3 e9 edraw(G, pos=None, ax=None, **kwds) draw_networkx(G, pos=None, arrows=True, with_labels=True, **kwds)
0 u3 w$ k& v3 @% i' Z$ ^+ ?常用的属性定义如下:
; v- {1 J; R+ s- p4 w& `" w' N* ~6 o* v/ F# Y( v. l
‘node_size’:指定节点的尺寸大小,默认300
! r3 z N' r! T. K( _- p. z1 P8 A‘node_color’:指定节点的颜色,默认红色3 T$ K% t6 |# J/ [ z
‘node_shape’:节点的形状,默认圆形
- z. N/ K+ }4 k8 Z- k+ k'‘alpha’:透明度,默认1.0,不透明) h* F3 l, P2 S5 {: D3 z {0 w9 t9 F
‘width’:边的宽度,默认1.0
$ _ o4 Z- h0 f# \+ ^, \. S‘edge_color’:边的颜色,默认黑色
) p+ {; m1 t$ F' ^1 G8 F‘style’:边的样式,可选 ‘solid’、‘dashed’、‘dotted’、‘dashdot’
) ~/ _: P$ t& V% |‘with_labels’:节点是否带标签,默认True( m8 [+ {& n/ t& u4 U: j
‘font_size’:节点标签字体大小,默认12
) d1 @+ U* k) T" B |! u9 h. P‘font_color’:节点标签字体颜色,默认黑色8 V$ C; u4 O: i5 `8 d9 G
1 T# E5 n M3 n+ V/ Q6 |
4 w5 I5 [9 I' }4 }6 v3 Q- S; q# ^2 f7 c# R
3.2 图的分析NetwotkX 提供了图论函数对图的结构进行分析0 H3 g# `( S. r2 g. V" P5 ?
子图
7 l9 g2 j. P! w4 R6 h$ Z2 [2 x- 子图是指顶点和边都分别是图 G 的顶点的子集和边的子集的图。
- subgraph()方法,按顶点从图 G 中抽出子图。例程如前。
4 J# h+ ^* l: s6 O" r8 {7 p% S$ [ 连通子图2 U: j) x% d; ^7 z4 N5 C
) s3 L5 F9 p$ ^. a8 A7 ?' w, R
- 如果图 G 中的任意两点间相互连通,则 G 是连通图。
- [color=rgba(0, 0, 0, 0.749019607843137)]connected_components()方法,返回连通子图的集合。, m4 T% n9 U3 D6 r2 |( j" y" b
[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}]
3 }' m/ K, y$ j0 W( B # s7 s! J+ u, |8 m9 m0 i' |1 _
4 ]8 u: `8 `; A% G0 |
+ A. ]3 n: `. R9 [5 q5 u, i
1 _) @% T$ s( \' \- n( s |