每天早高峰,你站在地铁线路图前,看到的是站点与轨道编织成的一张网。这张图刻意省略了地理距离——五棵松和海淀黄庄之间实际隔了几公里并不重要,重要的是“它们是不是相邻的两站”。计算机科学家把这种“只关心谁和谁相连”的抽象方式,叫做图(Graph)。 图由两个基本零件组成:像地铁站点一样的节点,和像轨道一样的边。如果把微信好友、分子原子、城市路口都放进这个模型里,你会惊喜地发现:它们全都是“站点+轨道”的变装。而这正是当下大热的图神经网络(GNN)的第一块地基——机器要读懂关系型数据,先要会表示这张“网”。 这篇文章会用地铁系统的语言,带你认识图神经网络大门前的所有基础概念:节点、边、邻接矩阵、度、图的类型与属性。学完以后,你再看社交推荐、分子预测、路径规划这些AI应用,会多出一双“看穿结构”的眼睛。

岗位关联

图数据是推荐系统、社交分析、分子发现与路径规划的共同底座。掌握图的概念,等于拿到进入GNN世界的首张通行证——对AI从业者而言,这是处理关系型数据必备的基础能力。

目录
  1. 可视化演示
  2. 图的定义
  3. 节点与边
  4. 邻接矩阵
  5. 图的类型
  6. 图的属性
  7. 图的应用
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

展示图的节点边结构、有向无向边类型,以及邻接矩阵的数学表示,直观理解图数据的组织方式。

本节配有交互动效(进入视口后自动加载,约 3KB)。

图结构与边类型 节点表示实体对象,边表示实体间的关系,图能自然表达社交网络等复杂数据 无向边没有方向性,有向边具有方向,边可带权重表示关系强度 节点的度数表示连接的边数,有向图分为入度和出度 G = (V, E) 图由节点集合V和边集合E构成。

图的定义

每天早高峰,你站在地铁线路图前,看到的是站点与轨道编织成的网。这张图刻意省略了地理距离——五棵松和海淀黄庄之间实际隔了几公里并不重要,重要的是“它们是相邻的两站”。计算机科学家把这种“只关心谁和谁相连”的抽象方式,称为图。图的迷人之处,正在于它敢于丢弃次要信息,只保留关系本身。

顺着这个思路,图用两个集合描述世界。第一个集合装下所有研究对象,叫顶点集,记作V,地铁图中就是每一个站点;第二个集合装下所有连接关系,叫边集,记作E,站与站之间的轨道就是一条条边。把这两个集合打包进一个括号,就得到了一张完整的图。

举一个具体的例子。假设一张迷你地铁图只有A、B、C三个站,A与B、B与C之间通着轨道,那么 \( V=\{A,B,C\} \),\( E=\{(A,B),(B,C)\} \)。城市再大,图的骨架也不过是这两份清单。AI处理图数据时,第一步就是把对象与关系整理成计算机能读的结构。

1. 顶点集 V:图中所有节点的集合,地铁图里就是全部站点的名录。

V={v1,v2,…,vn}\displaystyle V = \{v_1, v_2, \ldots, v_n\}

2. 边集 E:所有“谁连谁”的关系,每条边连接两个顶点。

E={e1,e2,…,em},ek=(vi,vj)\displaystyle E = \{e_1, e_2, \ldots, e_m\}, \quad e_k = (v_i, v_j)

3. 元组打包:用圆括号把顶点集和边集合成一个整体,得到图。

G=(V,E)\displaystyle G = (V, E)

下次等地铁时再看线路图,你会发现自己已经拥有了“图视角”:任何复杂系统,都可以先问一句——对象是什么?连接是什么?把这两个问题回答清楚,你就画出了一张图的骨架。

tex1 行
\displaystyle G = (V, E)

节点与边

走进任何一座地铁站,你第一眼看到的是站名和换乘标识。同一个站,多条线路交汇,就像一个人同时是程序员、长跑爱好者、猫奴——这些“标签”是节点自带的特征。而站与站之间的轨道,可能长3公里也可能长15公里,可能在地上也可能在地下——这些属性是边的特征。节点与边,就是图世界的“原子”与“化学键”。

有了节点和边,第一个要回答的问题是“这个节点有多重要”。地铁调度员会告诉你:看它连着几条轨道。一个站直接连通的轨道数,就是它的度。度越大的站,越是网络中的枢纽。在三环线上,某个换乘站连着四五条线路,度就高;一个偏僻的终点站只有一条线路,度就是1。

为了把“度”说精确,我们引入邻居的概念:与某个节点直接相连的其他节点,叫它的邻居。节点v的度,等于它有多少个邻居。

deg⁡(v)=∣N(v)∣\displaystyle \deg(v) = |N(v)|

1. 邻居集合 N(v):先找出所有与v直接相连的节点。

N(v)={u∈V:(u,v)∈E}\displaystyle N(v) = \{u \in V : (u, v) \in E\}

2. 集合大小:竖线 |·| 表示“这个集合里有多少个元素”。

∣N(v)∣=邻居的数量\displaystyle |N(v)| = \text{邻居的数量}

3. 度即邻居数:把两步合在一起,度就是邻居的数量。

deg⁡(v)=∣N(v)∣\displaystyle \deg(v) = |N(v)|

在无向图里,一条边为两端的节点各贡献1度,所以所有节点的度加起来等于边数的两倍——这个规律后面还会用到。度越大的节点,在地铁网里是换乘枢纽,在社交网络里就是“社牛”;在分子里,度大的原子往往是活泼的化学中心。读懂度,就迈出了理解图结构的第一步。

邻接矩阵

地铁调度中心不会把整面墙都挂上线路图,而是用一张巨大的表格管理“哪站通哪站”。这张表的最上面一行和最左边一列,依次列出全部站点;如果第i站和第j站之间通着轨道,就在第i行第j列的交叉格子里打一个勾。这张“打勾表”,就是邻接矩阵。

邻接矩阵是图在计算机里的“身份证”。它的规则简单到不能再简单:有边记1,无边记0。第i行第j列的元素,记录的是“第i个节点与第j个节点是否相连”。

Aij={1,(vi,vj)∈E0,otherwise\displaystyle A_{ij} = \begin{cases} 1, & (v_i, v_j) \in E \\ 0, & \text{otherwise} \end{cases}

1. 矩阵定位:\(A_{ij}\) 表示第 i 行第 j 列的格子,对应节点 \(v_i\) 与 \(v_j\)。

Aij=A[vi][vj]\displaystyle A_{ij} = A[v_i][v_j]

2. 判定条件:检查 \(v_i\) 和 \(v_j\) 之间是否存在一条边。

(vi,vj)∈E  ⟺  Aij=1\displaystyle (v_i, v_j) \in E \iff A_{ij} = 1

3. 分情况取值:存在边取1,否则取0,这就是完整的规则。

Aij={1,(vi,vj)∈E0,otherwise\displaystyle A_{ij} = \begin{cases} 1, & (v_i, v_j) \in E \\ 0, & \text{otherwise} \end{cases}

邻接矩阵有一个明显的坏处:空间复杂度。n个节点就需要 \(n \times n\) 个格子。5个站只要25格,1000个站就是100万个格。真实社交网络动辄数亿用户,矩阵会膨胀到天文数字。于是有了邻接表——只记录“有边的邻居”,像手机通讯录只存打过电话的人,稀疏图里又省空间又方便找邻居。邻接矩阵忠实但笨重,邻接表轻巧但查询稍慢,两者各有各的舞台。

图的类型

地铁隧道大多是双向的,但有些换乘通道只允许单向通行。如果轨道只允许从A站开向B站,不允许从B站开向A站,这就成了有向图。微博里你关注了大V,大V不一定关注你——这就是有向边;微信加好友必须双方同意,这就是无向图的“双向互通”。

现实世界中的图,很少只有“通”和“不通”两种状态。高速路按里程收费,导航按预计时间规划路线——这种每条边都带着一个数字的图,叫带权图。那串数字叫权重,可以是距离、时间、票价。另外还有连通图:从任意一个站出发,沿着轨道总能抵达任意另一个站,这说明整个网络是一体的;否则图会分裂成几个互不相通的板块。

不同类型图中,度的统计方式也不同。但无论怎么统计,无向图都遵守一条优美的规律:

∑v∈Vdeg⁡(v)=2∣E∣\displaystyle \sum_{v \in V} \deg(v) = 2|E|

1. 求所有度之和:把图中每个节点的度累加起来。

S=∑v∈Vdeg⁡(v)\displaystyle S = \sum_{v \in V} \deg(v)

2. 每条边贡献两次:一条边有两个端点,各被计入1度。

S=2∣E∣\displaystyle S = 2|E|

3. 合并恒等式:两步合起来,就是握手引理。

∑v∈Vdeg⁡(v)=2∣E∣\displaystyle \sum_{v \in V} \deg(v) = 2|E|

有向、带权、连通,这三个标签决定了图数据如何建模。社交推荐常用无向好友图,排行榜用有向关注图,路径规划用带权有向图。选定图的类型,就像选定地铁制式——是双轨还是单轨,要不要计费,是否全城成网,都直接影响后续的一切算法设计。

图的属性

从西直门到东直门,你可以坐2号线直达,也可以换乘4号线再转13号线——每一种走法都是一条路径。路径就是由边首尾相接组成的一条链,它回答了“怎么从A到B”的问题。在一张图里,路径可能有很多条,有的短、有的长、有的绕路。

路径的长度怎么算?在普通地铁图里,长度是“经过了几段轨道”;在带权图里,长度是“经过的轨道的时间或里程之和”。导航软件报出的“预计45分钟”,本质上就是一条带权路径的总权重。

L(P)=∑e∈Pw(e)\displaystyle L(P) = \sum_{e \in P} w(e)

1. 路径 P:一条从起点到终点的节点序列,相邻节点间都有边。

P=(v0,v1,…,vk)\displaystyle P = (v_0, v_1, \ldots, v_k)

2. 边权重求和:对路径上的每条边取权重并累加。

L(P)=∑e∈Pw(e)\displaystyle L(P) = \sum_{e \in P} w(e)

3. 无权图特例:每条边权重视为1,长度就是边数。

L(P)=∣P∣\displaystyle L(P) = |P|

路径走成一个圈,起点和终点重合,就成了环。地铁10号线就是一个环,列车绕着圈跑。环的存在让图变得更有趣:它意味着“循环依赖”,也意味着消息可以在图里反复流转。如果一张图分裂成几个互不相连的部分,每个部分内部连通、彼此隔绝,这些部分就叫连通分量——像同一座城市里两家地铁公司各跑各的、从不换乘。理解了路径、环与连通分量,你就掌握了图的结构骨架。GNN正是沿着路径传递消息,借助环形成深层表达,再在连通分量间做归纳。

图的应用

地铁图是图,但“站点+轨道”这个模型一旦抽象出来,仿佛获得了变形能力——换上不同的解释,就成了完全不同的领域。微信好友关系里,用户是节点,好友关系是边。推荐算法想推荐新朋友,就先看看“朋友的朋友”里有没有你认识的人,这正是图最朴素也最有效的应用。

药物研发中,分子被建模成分子结构图:原子是节点,化学键是边。传统程序靠人工设计分子特征,费时费力;GNN直接从图结构上学习,预测某个化合物有没有毒性、能不能溶解,帮助科学家在数以百万计的候选分子中快速筛选。这是图在科研领域最激动人心的舞台之一。

交通网络就更直观了:路口是节点,道路是边,红绿灯等待时间和里程是权重。外卖平台的骑手路线、地图导航的推荐方案,都是在带权图上寻找最短路径。可以说,推荐系统、金融风控、知识图谱、交通调度,全都建立在图的基础之上——图给了AI一双看清“联系”的眼睛。

回到地铁场景:你每天看的线路图,就是图神经网络的第一课。掌握了节点、边、邻接矩阵、度、图的类型与属性,你已经拿到了进入GNN世界的第一把钥匙。下一步,就是让神经网络学会“阅读”这张网上的信息流动。

AI 应用场景

社交好友推荐

阶段:数据表示与特征提取

解决的问题:传统协同过滤只看“用户-商品”打分矩阵,难以利用用户之间的社交关系。把用户建模为节点、好友关系建模为无向边,图结构天然携带“朋友的朋友”等高阶信息,推荐更精准。

具体案例:某社交App构建全员无向好友图,统计每个用户的二跳邻居(朋友的朋友)出现频次,按共同好友数排序生成“你可能认识的人”。对比传统协同过滤,推荐点击率提升约20%。

分子性质预测

阶段:模型输入构建

解决的问题:分子性质预测传统依赖手工专家特征,信息损失大。将分子表示为图——原子是节点,化学键是边,GNN直接在结构上学习,无需人工设计指纹特征。

具体案例:某药企用GNN预测化合物毒性与溶解度,将SMILES字符串转为分子图结构,在MoleculeNet公开数据集上AUC达到0.85以上,显著快于传统QSAR方法。

物流路径规划

阶段:推理与决策

解决的问题:配送路线优化传统靠人工经验,无法实时应对拥堵。把路网建模为带权有向图,权重=预估通行时间,再用图搜索算法求解最短路径。

具体案例:某外卖平台维护实时路网图,高峰期动态更新道路权重,骑手平均配送时长降低12%,超时率下降近三分之一。

Python 演示

python32 行
class Graph:    """无向图: 用邻接矩阵表示"""    def __init__(self, num_nodes):        self.num_nodes = num_nodes        self.adj_matrix = [[0] * num_nodes for _ in range(num_nodes)]     def add_edge(self, u, v):        self.adj_matrix[u][v] = 1        self.adj_matrix[v][u] = 1     def degree(self, v):        return sum(self.adj_matrix[v])     def neighbors(self, v):        return [i for i in range(self.num_nodes) if self.adj_matrix[v][i] == 1]     def print_matrix(self):        for row in self.adj_matrix:            print(' '.join(str(x) for x in row))  if __name__ == '__main__':    # 5个地铁站: 0=A 1=B 2=C 3=D 4=E    g = Graph(5)    edges = [(0, 1), (0, 2), (1, 2), (2, 3), (3, 4)]    for u, v in edges:        g.add_edge(u, v)     print('邻接矩阵:')    g.print_matrix()    print('C站(索引2)的度:', g.degree(2))    print('C站的邻居:', g.neighbors(2))
目的:用邻接矩阵实现一个无向图,演示添加边、统计节点度、查找邻居,并以A-E五站地铁图为例输出运行结果。
  1. self.adj_matrix = [[0] * num_nodes for _ in range(num_nodes)]用列表推导式创建 n×n 的全0矩阵。注意不能写成 [[0]*n]*n,否则每行是同一个列表的引用,改一行全部行都会变。
  2. self.adj_matrix[u][v] = 1在 u 行 v 列打上“有边”标记。
  3. self.adj_matrix[v][u] = 1无向图对称性:v 到 u 也必须标记。
  4. return sum(self.adj_matrix[v])求第 v 行的和,1 的个数就是该节点的度。
  5. return [i for i in range(self.num_nodes) if self.adj_matrix[v][i] == 1]扫描 v 行,值为 1 的列索引就是邻居。
  6. g = Graph(5)创建5节点图,模拟A-E五个地铁站。
  7. for u, v in edges: g.add_edge(u, v)逐条铺设边,构建迷你地铁网。

常见误区

误区一听到“图”,就想到照片、插画、Excel折线图,以为“图神经网络”就是处理图像的神经网络。

正解此“图”非彼“图”。在数据结构中,图是“节点+边”的关系网络。地铁线路图、微信好友关系、分子结构都是图;而照片是像素矩阵,属于图像。图神经网络处理的是关系网络,不是像素。

为何常见:中文“图”一词多义,加上“图神经网络”与“图像识别”两个领域中文名相近,初学者极易混淆。

误区既然树是图的一种,那么所有图都像树一样有根节点、有层次结构、没有环。

正解树是无环连通图的一个特例,但一般图可以有环、可以有孤立节点、可以不连通。地铁10号线是环,微博互关形成的循环也是环——它们都是图,但都不是树。

为何常见:大多数学习者先接触二叉树,“分层”的印象根深蒂固,容易把树的限制错当成图的性质。

误区学完邻接矩阵后,觉得这种表示简单又直观,认为所有图都应该用矩阵来存。

正解矩阵占 \(O(V^2)\) 空间,稀疏图(边很少)浪费巨大。十亿用户的社交网络根本存不下。邻接表只记录有边的邻居,稀疏图下既省内存,遍历邻居也更快。两种表示要看图的稀疏程度来选择。

为何常见:课堂上的小例子只有5个节点,矩阵看着整齐又美观,掩盖了数据规模爆炸时的问题。

误区数度的时候,觉得一条无向边被两个端点各算一次是多算了,认为总度应该等于边数。

正解无向图中一条边确实为两个端点各贡献1度,所以总度等于 \(2|E|\)。这不是多算,而是握手引理的本质:每个度代表一次“端点关联”。A-B一条边,A的度加1,B的度也加1,总共加2。

为何常见:有向图里入度和等于边数,先学有向图再学无向图时,容易把两种统计方式搞混。

误区把有向图的度也简单数成“邻居个数”,忽略边的方向。

正解有向图的边有方向。入度=指向自己的边数,出度=自己指出的边数。微博里你关注别人是出度,别人关注你是入度。入度和=出度和=边数,这是有向图独有的规律。

为何常见:无向图“度=邻居数”太简洁经典,学到有向图时思维没有切换,把方向信息丢掉了。

面试题

Q1. 图 \(G=(V, E)\) 中的 V 表示什么?

单选题 · easy

  • A.边的集合
  • B.顶点的集合← 正确答案
  • C.邻居的集合
  • D.矩阵的集合

答案:B。图由顶点集 V 和边集 E 组成,V 是全部节点的集合,E 是全部边的集合。地铁图中站点是 V,轨道是 E。A 描述的是 E,C、D 与定义无关。

Q2. 无向图中节点 v 的度等于什么?

单选题 · easy

  • A.全图节点数
  • B.邻居节点数← 正确答案
  • C.边的总数
  • D.矩阵对角线元素

答案:B。无向图中度定义为邻居节点的个数,即与 v 直接相连的节点数。地铁站连着几个站,度就是几。C 是整张图的边数,与单个节点的度无关。

Q3. 一个无向图有10个节点,每个节点的度都是3,则图中边的总数是多少?

单选题 · mid

  • A.等于10条边
  • B.等于15条边← 正确答案
  • C.等于20条边
  • D.等于30条边

答案:B。由握手引理,所有节点度之和等于 \(2|E|\)。这里度之和为 \(10 \times 3 = 30\),所以 \(2|E|=30\),解得 \(|E|=15\)。30 是度之和,不是边数。

Q4. 邻接矩阵中 \(A[i][j]=1\) 表示什么?

单选题 · easy

  • A.i到j没有连线
  • B.i和j之间有条边← 正确答案
  • C.i的度数等于j
  • D.i是j的邻居

答案:B。邻接矩阵规则是有边记1、无边记0,\(A[i][j]=1\) 说明第 i 个节点和第 j 个节点之间存在一条边。A 说反了,C、D 是度的概念而非矩阵元素含义。

Q5. 有向图节点 v 的入度为2、出度为3,以下说法正确的有?

多选题 · mid

  • A.总度数等于5← 正确答案
  • B.总度为入度加出度← 正确答案
  • C.邻居数一定是5
  • D.出度大于入度← 正确答案

答案:ABD。有向图节点总度=入度+出度=2+3=5,A、B 正确;出度3大于入度2,D 正确。C 错误——有向图中邻居分前驱和后继,不能简单说邻居一共5个。

Q6. 关于邻接矩阵,下列说法正确的有?

多选题 · mid

  • A.无向图的矩阵对称← 正确答案
  • B.空间复杂度较大← 正确答案
  • C.稀疏图更省空间
  • D.对角线一定为0

答案:AB。无向图边无方向,所以 \(A[i][j]=A[j][i]\),矩阵对称,A 正确;矩阵占 \(O(V^2)\) 空间,B 正确。稀疏图用邻接表更省空间,C 错误;对角线在存在自环时才非0,不能说一定为0,D 错误。

Q7. 有向图中所有节点的入度之和等于什么?

单选题 · hard

  • A.节点总数总和
  • B.边的总数目← 正确答案
  • C.出度和的一半
  • D.节点数的两倍

答案:B。有向图中每条边恰好贡献1个入度和1个出度,所以所有入度之和=所有出度之和=边数。类比单向通道:每条单行道只有一个入口和一个出口,入口总数等于道路总数。

Q8. 以下哪些属于图的应用场景?

多选题 · hard

  • A.社交网络推荐← 正确答案
  • B.分子结构建模← 正确答案
  • C.导航路径规划← 正确答案
  • D.数组快速排序

答案:ABC。社交网络用好友关系图做推荐,分子用原子-键图建模性质,导航用路网图规划路径,三者都是图的典型应用。快速排序是数组上的算法,与图结构无关。

Q9. 一个有向图的邻接矩阵中,非零元素的个数等于什么?

单选题 · extreme

  • A.节点总数个数
  • B.边的总数个数← 正确答案
  • C.两倍边的个数
  • D.度数之和大小

答案:B。有向图每条边对应矩阵中的一个非零元素(只记一次方向)。而无向图因对称性,每条边会出现在两个对称位置,所以非零元素是边数的两倍。此题考的是有向图与无向图在矩阵表示上的关键区别。

Q10. 在带权图中,一条路径的长度是指什么?

单选题 · mid

  • A.经过的边权重和← 正确答案
  • B.经过的节点数量
  • C.起点到终点距离
  • D.经过的边数量

答案:A。带权图中路径长度=路径上所有边的权重之和,如导航中的预计时间总和。B 是节点数,D 是无权图的长度,C 的“直线距离”忽略了实际路径,均不正确。