Python小白的数学建模课-图论的基本概念
! t% x E; t# H$ {' W3 _$ H2 d4 ?+ ?7 I/ {3 n6 Y+ i
- 图论中所说的图,不是图形图像或地图,而是指由顶点和边所构成的图形结构。
- 图论不仅与拓扑学、计算机数据结构和算法密切相关,而且正在成为机器学习的关键技术。
- 本系列结合数学建模的应用需求,来介绍 NetworkX 图论与复杂网络工具包的基本功能和典型算法。+ ?% w; l) o0 ]5 F8 \1 Z5 d; `7 W
9 d# A4 r5 c# y! q& b% v1. 图论1.1 图论是什么
5 f" h7 h9 O6 N8 v# x图论〔Graph Theory〕以图为研究对象,是离散数学的重要内容。图论不仅与拓扑学、计算机数据结构和算法密切相关,而且正在成为机器学习的关键技术。1 [- n1 m1 N% M2 A) O6 E8 R- [
2 F: ~# C/ z7 j! j. P2 l6 r图论中所说的图,不是指图形图像(image)或地图(map),而是指由顶点(vertex)和连接顶点的边(edge)所构成的关系结构。
w' u j3 X7 c# l9 n
4 C# \' ]- M: M, t8 \图提供了一种处理关系和交互等抽象概念的更好的方法,它还提供了直观的视觉方式来思考这些概念。
! B6 E, p; p1 y( W# M
4 U6 B" ~$ H/ F. Q1.2 NetworkX 工具包5 _1 ]' F1 B5 n1 E
NetworkX 是基于 Python 语言的图论与复杂网络工具包,用于创建、操作和研究复杂网络的结构、动力学和功能。
5 P# d* N! K$ v, o3 {8 g" } t. Q. u
NetworkX 可以以标准和非标准的数据格式描述图与网络,生成图与网络,分析网络结构,构建网络模型,设计网络算法,绘制网络图形。
& K# T, K% i" @6 [5 Z. w( v: o: P1 c, w; B, x \8 B& z
NetworkX 提供了图形的类、对象、图形生成器、网络生成器、绘图工具,内置了常用的图论和网络分析算法,可以进行图和网络的建模、分析和仿真。
4 u7 q8 ^" Y, U/ B2 d( y, c
" s6 B5 `# x$ ^9 u4 [NetworkX 的功能非常强大和庞杂,所涉及内容远远、远远地超出了数学建模的范围,甚至于很难进行系统的概括。本系列结合数学建模的应用需求,来介绍 NetworkX 图论与复杂网络工具包的基本功能和典型算法。
6 Q4 ?0 N3 W1 a1 F3 c/ `
O6 \3 p+ b9 X" Y% b# j / c q, H( K6 }; x! o( K3 R C
2、图、顶点和边的创建与基本操作
0 }2 F, j* L/ \+ s5 _- k7 M* X图由顶点和连接顶点的边构成,但与顶点的位置、边的曲直长短无关。 Networkx 支持创建简单无向图、有向图和多重图;内置许多标准的图论算法,节点可为任意数据;支持任意的边值维度,功能丰富,简单易用。 2.1 图的基本概念
" o5 a7 l( F6 O) h6 ]: F图(Graph):图是由若干顶点和连接顶点的边所构成关系结构。
3 z! E/ N9 V, S" v4 p0 g顶点(Node):图中的点称为顶点,也称节点。) \' ^, m& w* ~; J) o$ h/ A
边(Edge):顶点之间的连线,称为边。8 Y' i: r/ g* ]( o3 i
平行边(Parallel edge):起点相同、终点也相同的两条边称为平行边。
3 P6 H- d: g) m2 m循环(Cycle):起点和终点重合的边称为循环。# x: @) _2 [, U( l4 `( ~. ^
有向图(Digraph):图中的每条边都带有方向,称为有向图。
# U5 [: [ d( O4 E( B9 Y% U J无向图(Undirected graph):图中的每条边都没有方向,称为无向图。
; X1 Y( ^% z+ M/ X8 M1 ~. _赋权图(Weighted graph):图中的每条边都有一个或多个对应的参数,称为赋权图。该参数称为这条边的权,权可以用来表示两点间的距离、时间、费用。
- w* E7 z# ]. P: J% R" O度(Degree):与顶点相连的边的数量,称为该顶点的度。
- Z _4 P) z9 b9 L* @! o
: f7 T& P; P) t3 F2.2 图、顶点和边的操作
% t: K5 H) o) ?$ j: z0 }; C9 t. U9 ANetworkx很容易创建图、向图中添加顶点和边、从图中删除顶点和边,也可以查看、删除顶点和边的属性。& I; b- q2 W+ u, f8 k4 y( v z
3 N1 N" x/ S8 s* K) _3 e1 s/ _# U2.2.1 图的创建Graph() 类、DiGraph() 类、MultiGraph() 类和 MultiDiGraph() 类分别用来创建:无向图、有向图、多图和有向多图。定义和例程如下:
; {1 u8 t$ V* J. E
. z: K; w8 K/ {+ B1 E# pclass Graph(incoming_graph_data=None, **attr) `. v6 T" s6 D7 ?3 P/ p; |* l
import networkx as nx # 导入 NetworkX 工具包
' X. k. M8 I- X6 }! U8 E9 Q+ J0 u! O5 K6 M$ z" y
# 创建 图
) N9 B5 X1 w& g( ^$ h- VG1 = nx.Graph() # 创建:空的 无向图- W5 V( o; U& Q4 S0 @ ?
G2 = nx.DiGraph() #创建:空的 有向图
/ I4 `. Z) a' m4 i8 `& V! RG3 = nx.MultiGraph() #创建:空的 多图3 C ]9 b. j4 F7 a2 f/ P/ p
G4 = nx.MultiDiGraph() #创建:空的 有向多图: m- }( V1 ~- q2 G2 c
- ~$ N1 I5 [+ H
, G3 W% R3 E' L6 E" N: d2.2.2 顶点的添加、删除和查看+ [& f& b' B5 k
图的每个顶点都有唯一的标签属性(label),可以用整数或字符类型表示,顶点还可以自定义任意属性。 顶点的常用操作:添加顶点,删除顶点,定义顶点属性,查看顶点和顶点属性。定义和例程如下:
, i, s4 \$ M8 q8 g$ h8 s1 Y# EGraph.add_node(node_for_adding, **attr)+ t4 v* \9 ?6 a- H$ v
Graph.add_nodes_from(nodes_for_adding, **attr)
/ f4 w- {- R' [0 SGraph.remove_node(n): ~% t+ f0 L" }9 ~/ r
Graph.remove_nodes_from(nodes)* o) l: U9 R5 B7 @2 I* |
) P2 b; m5 e& e% U2 r9 @2 l
# 顶点(node)的操作1 c) F! [* L4 l f6 W: U/ i$ h
# 向图中添加顶点" K' z3 i: W5 a) c. o3 v8 E
G1.add_node(1) # 向 G1 添加顶点 1
( }/ ~: K; N7 f7 s/ ^8 A, YG1.add_node(1, name='n1', weight=1.0) # 添加顶点 1,定义 name, weight 属性
! w5 y# Z7 g( a5 @& z- RG1.add_node(2, date='May-16') # 添加顶点 2,定义 time 属性6 K+ G) [' P A& B8 g
G1.add_nodes_from([3, 0, 6], dist=1) # 添加多个顶点,并定义属性+ j5 S4 M$ T. g4 b
G1.add_nodes_from(range(10, 15)) # 向图 G1 添加顶点 10~14; r6 J! k# O3 Y: q8 I4 F
9 ~* }% F& `4 `6 D, X- v( [4 Y f
# 查看顶点和顶点属性9 R" O: c: z) E8 T: a$ E
print(G1.nodes()) # 查看顶点列表
( Z$ V: V. H. I4 G! w# [1, 2, 3, 0, 6, 10, 11, 12, 13, 14]
o7 l2 C6 \1 U0 \print(G1._node) # 查看顶点属性
" |- D% A- L* {' A; N9 ~# {1: {'name': 'n1', 'weight': 1.0}, 2: {'date': 'May-16'}, 3: {'dist': 1}, 0: {'dist': 1}, 6: {'dist': 1}, 10: {}, 11: {}, 12: {}, 13: {}, 14: {}}
3 x# Q* v# y% O' T; A a0 R8 i
4 i/ w$ p" V) l7 L. W0 L/ Q+ E# 从图中删除顶点
% D; T) t$ J# F$ f+ X& MG1.remove_node(1) # 删除顶点
6 _! Y* \* O) b' s, ?G1.remove_nodes_from([1, 11, 13, 14]) # 通过顶点标签的 list 删除多个顶点' s3 ?( j: [$ _$ _9 s- s& F
print(G1.nodes()) # 查看顶点5 o8 Y5 y2 y2 X8 w. a
# [2, 3, 0, 6, 10, 12] # 顶点列表; X; [' h( R9 M1 S7 e- v8 T' H
2.2.3 边的添加、删除和查看边是两个顶点之间的连接,在 NetworkX 中 边是由对应顶点的名字的元组组成 e=(node1,node2)。边可以设置权重、关系等属性。 边的常用操作:添加边,删除边,定义边的属性,查看边和边的属性。向图中添加边时,如果边的顶点是图中不存在的,则自动向图中添加该顶点。 Graph.add_edge(u_of_edge, v_of_edge, **attr)' L$ n" P9 t% t4 v+ b% W
Graph.add_edges_from(ebunch_to_add, **attr)% L! y% J# i. w* }5 ^: C( w
Graph.add_weighted_edges_from(ebunch_to_add, weight=‘weight’, **attr)5 Y( n" H' Z# Y( X# z
& U; W# E- S+ Y! h, b8 a. r
# 边(edge)的操作
$ y G+ v7 y# \8 G- F: y& D# 向图中添加边
: e6 [ Q4 F3 }* b2 ]8 A( t$ H' X8 l TG1.add_edge(1,5) # 向 G1 添加边,并自动添加图中没有的顶点
5 K5 J3 P! O& v9 YG1.add_edge(0,10, weight=2.7) # 向 G1 添加边,并设置边的属性
) W. }1 u" W M8 k7 B) ?G1.add_edges_from([(1,2,{'weight':0}), (2,3,{'color':'blue'})]) # 向图中添加边,并设置属性
0 y; G8 q2 \& ~: I' O& F. GG1.add_edges_from([(3,6),(1,2),(6,7),(5,10),(0,1)]) # 向图中添加多条边
) m- L! W: H [) c- R6 U. lG1.add_weighted_edges_from([(1,2,3.6),[6,12,0.5]]) # 向图中添加多条赋权边: (node1,node2,weight)0 {8 A9 `& k4 U; Z0 {9 N- I
print(G1.nodes()) # 查看顶点+ `+ X: y' o: K) T. Z% A6 M
# [2, 3, 0, 6, 10, 12, 1, 5, 7] # 自动添加了图中没有的顶点0 A- |) p* T6 B, ]" e
9 p6 ? o/ T+ a& ~0 p8 R# 从图中删除边4 F3 W- x+ V' ~) E7 f0 w
G1.remove_edge(0,1) # 从图中删除边 0-1
) C5 t& d q# d7 N' @0 fG1.remove_edges_from([(2,3),(1,5),(6,7)]) # 从图中删除多条边
: [8 D2 D% n8 W/ i \
6 b6 g7 V: D9 c. E4 g& p2 F# 查看 边和边的属性
' u& @0 J$ u. t& s0 Z w1 cprint(G1.edges) # 查看所有的边
4 v5 G" \6 v+ x5 ^% ]( C[(2, 1), (3, 6), (0, 10), (6, 12), (10, 5)]
/ x2 n% s& S7 Z# \+ Zprint(G1.get_edge_data(1,2)) # 查看指定边的属性! Q: t5 j2 i8 x1 D' l. ^
# {'weight': 3.6}
6 o+ h2 {2 F; _9 D9 {- b2 r# J \' V) zprint(G1[1][2]) # 查看指定边的属性' [" g+ Q, Z7 h: x J
# {'weight': 3.6}
1 C |+ L" {# z4 q9 C/ nprint(G1.edges(data=True)) # 查看所有边的属性
. @; Z% p# e9 S5 ^) U. [# [(2, 1, {'weight': 3.6}), (3, 6, {}), (0, 10, {'weight': 2.7}), (6, 12, {'weight': 0.5}), (10, 5, {})]
1 G9 o6 W; f; k6 u+ ]6 P& t9 `. Y: N6 m7 B) N
2.2.4 查看图、顶点和边的信息
, C- c: P7 \" j' K: g' k1 ]1 K- o; m- f7 ^% @5 ]5 ?
# 查看图、顶点和边的信息
0 t4 ^# {* A; W H* Jprint(G1.nodes) # 返回所有的顶点 [node1,...]4 F2 a+ K/ X5 y3 j
# [2, 3, 0, 6, 10, 12, 1, 5, 7], `7 s% ]/ a/ L3 g
print(G1.edges) # 返回所有的边 [(node1,node2),...]
" s- H7 P; B0 k' x# [(2, 1), (3, 6), (0, 10), (6, 12), (10, 5)]
! n0 Z7 Q9 M/ w# o8 @ Bprint(G1.degree) # 返回各顶点的度 [(node1,degree1),...]& L5 C* H) g k; I# {
# [(2, 1), (3, 1), (0, 1), (6, 2), (10, 2), (12, 1), (1, 1), (5, 1), (7, 0)]% U- V! e. Q" z/ w) I5 O$ Q0 Y, z# y
print(G1.number_of_nodes()) # 返回顶点的数量/ R0 e! n6 ]" g* G2 Y( K- @ k, [
# 9 b6 A0 J H& J+ E) n4 G
print(G1.number_of_edges()) # 返回边的数量
2 ]" H4 h: { S- u# 5" m5 n; o. m4 q9 k( {$ P
print(G1[10]) # 返回与指定顶点相邻的所有顶点的属性
- z- }( H5 p/ {# {0: {'weight': 2.7}, 5: {}}2 N$ p2 B5 Q% w
print(G1.adj[10]) # 返回与指定顶点相邻的所有顶点的属性( W! n9 U3 l& h- N
# {0: {'weight': 2.7}, 5: {}}
, [2 i. P) j b7 j# p# Dprint(G1[1][2]) # 返回指定边的属性
4 w6 p. f" |, ^3 N5 V# {'weight': 3.6}
- Z+ T- B* f- b3 M9 ^print(G1.adj[1][2]) # 返回指定边的属性7 u- x% n/ ?. B2 [2 l( E" {3 B4 J
# {'weight': 3.6}; K; `6 {: Q' G" \" H
print(G1.degree(10)) # 返回指定顶点的度
7 } z( D* `' @6 l# 2
5 C& J4 P5 \+ V4 ^- O3 t3 D: L" w6 o% P; x8 ^) M$ ^9 b& W, u
print('nx.info:',nx.info(G1)) # 返回图的基本信息
; w( |: i/ v2 x4 \1 Y3 z( Wprint('nx.degree:',nx.degree(G1)) # 返回图中各顶点的度/ V0 ]7 p7 w1 n! q+ Z7 v
print('nx.density:',nx.degree_histogram(G1)) # 返回图中度的分布
) j ]) M& f7 @1 d7 N" hprint('nx.pagerank:',nx.pagerank(G1)) # 返回图中各顶点的频率分布, k( o$ J2 [( \, W# A, N
, ?8 t6 h6 M9 n& C2 ?. ~4 R C" b! E% P9 i% V4 n8 z# ~8 i
1 Q! P3 }* W. b* f" z
2 z: l/ f* V. F* L4 h% Q2 R
# g9 } g% ^3 }; }1 s- q F2.3 图的属性和方法图的方法! S% }. L8 ]8 E/ i: S
- W* T+ J. \0 L& c- U' `# X方法 说明
5 [9 p, O( P; ]" P mG.has_node(n) 当图 G 中包括顶点 n 时返回 True% E, }3 m! A) n8 ?" h+ f/ o
G.has_edge(u, v) 当图 G 中包括边 (u,v) 时返回 True, t3 s3 Y. f+ j0 D* E
G.number_of_nodes() 返回 图 G 中的顶点的数量
5 g5 P4 A- I# E) ?+ K A* dG.number_of_edges() 返回 图 G 中的边的数量
$ b: }' f g5 Q! A( Q% z' `( MG.number_of_selfloops() 返回 图 G 中的自循环边的数量0 R* J0 j* N9 D; s% B4 u
G.degree([nbunch, weight]) 返回 图 G 中的全部顶点或指定顶点的度* R& ~- d \! ]) z2 D7 j
G.selfloop_edges([data, default]) 返回 图 G 中的全部的自循环边9 B/ f0 V# }/ r" U
G.subgraph([nodes]) 从图 G1中抽取顶点[nodes]及对应边构成的子图' G! i+ s8 Y- B% ]. }# i; L
union(G1,G2) 合并图 G1、G21 |7 n: `4 M8 L% R3 G
nx.info(G) 返回图的基本信息/ s5 B1 s' B6 v
nx.degree(G) 返回图中各顶点的度4 A; o7 D! i4 w4 I
nx.degree_histogram(G) 返回图中度的分布
' K: v) d Y' I4 n+ [4 Ynx.pagerank(G) 返回图中各顶点的频率分布
& R# R7 b2 y* j- X. lnx.add_star(G,[nodes],**attr) 向图 G 添加星形网络- r6 p5 ]* b/ p0 Q& ?; K3 x0 w# k
nx.add_path(G,[nodes],**attr) 向图 G 添加一条路径" l. K [4 x* w9 C9 y
nx.add_cycle(G,[nodes],**attr) 向图 G 添加闭合路径$ _# ~* b% }; L5 k& d: }5 D" E
' s' V+ o! P. ^, G: A |* g6 [
8 s: ?# N( l9 f; S8 P例程:( `# l G: B; i' Q
G1.clear() # 清空图G1
1 y d; L" {5 L4 h" t o9 Anx.add_star(G1, [1, 2, 3, 4, 5], weight=1) # 添加星形网络:以第一个顶点为中心
) n1 s. S: E$ N! L; E6 @# [(1, 2), (1, 3), (1, 4), (1, 5)]
. }) y( A. M( z: t4 d3 Tnx.add_path(G1, [5, 6, 8, 9, 10], weight=2) # 添加路径:顺序连接 n个节点的 n-1条边 |6 F \2 R$ `( u* V3 L1 [
# [(5, 6), (6, 8), (8, 9), (9, 10)]
: R* X+ h- H6 L" I3 h0 e- Lnx.add_cycle(G1, [7, 8, 9, 10, 12], weight=3) # 添加闭合回路:循环连接 n个节点的 n 条边
+ s5 P, f: p! F2 @4 i' L& I) y# [(7, 8), (7, 12), (8, 9), (9, 10), (10, 12)]* c% `2 ]" y( u. r- M9 t+ ~
print(G1.nodes) # 返回所有的顶点 [node1,...]3 y2 P }. \2 q3 g* s% p" h6 \, L
nx.draw_networkx(G1)! M4 a$ {0 G" V/ F- p( F$ r
plt.show()
4 a1 Y. {9 h& E% X7 Z* Z7 S5 L( R" W
G2 = G1.subgraph([1, 2, 3, 8, 9, 10])9 i+ ~8 X4 c+ _' L
G3 = G1.subgraph([4, 5, 6, 7])8 U: M! u8 _! ?
G = nx.union(G2, G3)
& I5 a7 |) r) o% Nprint(G.nodes) # 返回所有的顶点 [node1,...]# Y& I% {7 m- T0 T- c( h+ }# i
# [1, 2, 3, 8, 9, 10, 4, 5, 6, 7]. A) T7 m- ~6 Q
4 f. Z: s! h: a# i% M1 Y+ v
( `& m# ~+ N3 `6 t( Y7 v n) _% U4 f( n4 |3、图的绘制与分析3.1 图的绘制1 L% l1 `& j) `7 P
可视化是图论和网络问题中很重要的内容。NetworkX 在 Matplotlib、Graphviz 等图形工具包的基础上,提供了丰富的绘图功能。 b" [8 n4 S7 a8 @0 p6 S
& y8 ? _! R3 s! g本系列拟对图和网络的可视化作一个专题,在此只简单介绍基于 Matplotlib 的基本绘图函数。基本绘图函数使用字典提供的位置将节点放置在散点图上,或者使用布局函数计算位置。
" ]$ n% {7 L9 b0 w+ {& C5 L6 e* {; D* m6 A1 n2 e
方法 说明
' e. L" u4 S0 u: @) u: i( Xdraw(G[,pos,ax]) 基于 Matplotlib 绘制 图 G* a5 L. D: q* B. d4 }% k. t7 W+ s& v
draw_networkx(G[, pos, arrows, with_labels]) 基于 Matplotlib 绘制 图 G" d* X: }7 e6 x6 _! o1 A- r3 G
draw_networkx_nodes(G, pos[, nodelist, . . . ]) 绘制图 G 的顶点
6 \4 o8 H8 e+ Z- p! D0 Ndraw_networkx_edges(G, pos[, edgelist, . . . ]) 绘制图 G 的边% m, o8 s: T$ N9 H! N5 ]
draw_networkx_labels(G, pos[, labels, . . . ]) 绘制顶点的标签4 G3 v$ n* L( W g; v0 R
draw_networkx_edge_labels(G, pos[, . . . ]) 绘制边的标签( q, c( n6 |8 G* D5 C1 {( ?1 }# b
+ p! H3 `7 g8 ~6 [% y1 [: z4 O( U! V' k7 f; P$ j7 X: n
其中,nx.draw() 和 nx.draw_networkx() 是最基本的绘图函数,并可以通过自定义函数属性或其它绘图函数设置不同的绘图要求。
% f/ x- `2 W8 V' v; K5 _4 B {9 }7 P1 Odraw(G, pos=None, ax=None, **kwds) draw_networkx(G, pos=None, arrows=True, with_labels=True, **kwds) $ h/ R/ \+ D/ G9 T( q8 l+ m
常用的属性定义如下:$ X# ^" j( ^* H& c
( d5 y3 L$ t! T$ h, g‘node_size’:指定节点的尺寸大小,默认300
" f+ p H+ x( ^) o* B3 o) m‘node_color’:指定节点的颜色,默认红色; d( ^+ ~ G. p
‘node_shape’:节点的形状,默认圆形
: `5 B. M7 I/ L'‘alpha’:透明度,默认1.0,不透明% z3 T3 f) l8 V% O- k8 a
‘width’:边的宽度,默认1.0
& _/ |: C8 B3 b, G. n% O% D2 l& _‘edge_color’:边的颜色,默认黑色$ g/ {3 J k; C. a2 P3 z
‘style’:边的样式,可选 ‘solid’、‘dashed’、‘dotted’、‘dashdot’
; M. L% ]1 V( k) r‘with_labels’:节点是否带标签,默认True
% `- ?6 ]* C9 ?% }; t‘font_size’:节点标签字体大小,默认12
4 D: g/ E! [8 C/ {7 }; J" X! R, o‘font_color’:节点标签字体颜色,默认黑色
$ J8 T0 E+ o a6 t: C; |# p8 h0 L9 q# E$ ?
![]()
2 i- d; f( [+ j0 H, X g3 y$ m7 v* y3.2 图的分析NetwotkX 提供了图论函数对图的结构进行分析" e: d3 v# n& \. C
子图
/ p% n0 ]$ I1 O3 M. Q- Z- 子图是指顶点和边都分别是图 G 的顶点的子集和边的子集的图。
- subgraph()方法,按顶点从图 G 中抽出子图。例程如前。
5 ?1 ]6 D) v: G* b2 g% p2 R; O 连通子图4 L% X& ?9 t& i! i+ l1 }
; ]2 d; _3 T! d8 b- n- 如果图 G 中的任意两点间相互连通,则 G 是连通图。
- [color=rgba(0, 0, 0, 0.749019607843137)]connected_components()方法,返回连通子图的集合。% }( U b' @- A$ j
[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}]
8 o8 v; h/ v/ S, j+ y( _ 3 p1 e6 F, E+ C1 c! h; L9 f$ U
2 O: k p% Y) }" i; Q- t' S7 f$ V2 Q4 l6 X
/ r' \6 N4 n* S: N |