图论基础:从零开始认识图

各位同学,今天我们来聊聊图论。说实话,我第一次接触图论是在做支付网络风控的时候。当时要分析几百万个账户之间的资金流转关系,用传统的关系型数据库查得我头皮发麻。后来我才意识到,这不就是个图的问题吗?

图论听起来高大上,其实没那么玄乎。你想想看,微信好友关系、城市之间的航班、甚至你每天点的外卖配送路线,背后都是图在支撑。咱们今天就把图论的基础打牢。

图的基本概念:节点、边、度

先说说图到底长什么样。一个图由两部分组成:节点。节点就是图中的点,边就是连接点的线。

举个例子,假设我们要分析一个社交网络。每个用户就是一个节点,用户之间的好友关系就是一条边。就这么简单。

核心定义:

  • 节点(Vertex):图中的基本元素,也叫顶点。我习惯用 V 表示节点集合。
  • 边(Edge):连接两个节点的线,用 E 表示边的集合。
  • 度(Degree):一个节点连接的边的数量。说白了,就是你有几个邻居。

这里有个坑,我刚开始学的时候经常搞混。在无向图中,一个节点的度就是它有多少条边连着。但在有向图里,度要分成入度出度。入度是指向该节点的边数,出度是从该节点出发的边数。

我的经验:在金融网络中,节点的度往往能反映重要程度。比如一个银行账户如果出度特别高,说明它频繁向外转账,这可能是洗钱的特征。我曾经在反洗钱项目中就用这个特征抓到了几个异常账户。

图的类型:有向图、无向图、加权图

图不是千篇一律的,根据边的性质不同,我们可以把图分成几种类型。我个人觉得,理解这些类型比背定义重要得多。

无向图

无向图的边没有方向。就像微信好友关系,你加了我,我们就是好友,不分谁加谁。边用 (u, v) 表示,u 和 v 是对等的。

有向图

有向图的边有方向。就像微博关注,你关注了某大V,但大V不一定关注你。边用 <u, v> 表示,箭头从 u 指向 v。

注意:在金融网络中,资金流向天然就是有向的。A 转账给 B,和 B 转账给 A,完全是两码事。我见过有人用无向图分析资金流,结果把洗钱路径都搞反了。

加权图

加权图的每条边带有一个数值,叫权重。权重可以表示距离、成本、金额等。比如城市之间的航班,边上的权重就是飞行时间或票价。

加权图在金融领域太常见了。转账金额就是权重,交易手续费也是权重。我做过一个最优换汇路径的项目,每条边的权重就是汇率,我们要找一条让收益最大化的路径。

图类型 边的特点 金融应用场景
无向图 无方向,对称关系 企业关联关系、共同持股
有向图 有方向,非对称关系 资金转账、借贷关系
加权图 边带权重 交易金额、汇率、风险评分

图的表示方法:邻接矩阵与邻接表

图在计算机里怎么存?这是个实际问题。我刚开始写代码时,用了个二维数组硬存,结果数据量一大就崩了。后来才学会用正确的表示方法。

邻接矩阵

邻接矩阵用一个二维数组来表示图。假设有 n 个节点,就建一个 n×n 的矩阵。如果节点 i 和节点 j 之间有边,矩阵的 (i, j) 位置就填 1(或权重值),否则填 0。

# 邻接矩阵示例 - 无向图
# 节点: A, B, C, D
# 边: A-B, A-C, B-D, C-D

adj_matrix = [
    [0, 1, 1, 0],  # A 的邻居
    [1, 0, 0, 1],  # B 的邻居
    [1, 0, 0, 1],  # C 的邻居
    [0, 1, 1, 0]   # D 的邻居
]

# 检查 A 和 C 是否相连
print(adj_matrix[0][2])  # 输出 1,表示相连

优缺点分析:

  • 优点:判断两个节点是否相连,时间复杂度 O(1),快得很。
  • 缺点:空间复杂度 O(n²),节点一多就炸。10000 个节点就要 1 亿个格子。

邻接表

邻接表用列表或字典来存每个节点的邻居。每个节点后面跟着一个列表,里面是它所有邻居的编号。

# 邻接表示例 - 有向图
# 节点: 1, 2, 3, 4
# 边: 1->2, 1->3, 2->4, 3->4

adj_list = {
    1: [2, 3],
    2: [4],
    3: [4],
    4: []
}

# 获取节点 1 的所有邻居
print(adj_list[1])  # 输出 [2, 3]

# 加权图用元组存 (邻居, 权重)
weighted_adj_list = {
    1: [(2, 100), (3, 200)],
    2: [(4, 150)],
    3: [(4, 250)],
    4: []
}

我的建议:在实际项目中,我 90% 的情况都用邻接表。原因很简单——金融网络通常是稀疏的。几百万个账户,每个账户的交易对手可能只有几十个。用邻接矩阵存,内存根本扛不住。我曾经处理过一个 50 万节点的图,邻接矩阵要 2500 亿个格子,而邻接表只用了不到 2GB。

知识体系总览

下面这张图把本章的核心内容串起来了。我画这张图的时候,特意把三种图类型和两种表示方法放在一起对比,方便你理解它们之间的关系。

图论基础:核心知识体系 图 (Graph) 基本概念 节点 (Vertex) 边 (Edge) 度 (Degree) 入度 / 出度 图的类型 无向图 边无方向,对称关系 有向图 边有方向,非对称 加权图 边带权重值 表示方法 邻接矩阵 O(1) 查询,O(n²) 空间 邻接表 节省空间,适合稀疏图 核心:节点 + 边 → 构成图 → 分析关系

避坑指南:我曾经在做一个资金链路分析项目时,用邻接矩阵存了 10 万个节点的图。程序跑起来直接 OOM,服务器都卡死了。后来换成邻接表,内存占用从 40GB 降到了 500MB。所以记住:金融网络几乎都是稀疏图,用邻接表就对了

好了,图论的基础就这些。节点、边、度是核心三要素,有向无向加权是三种常见类型,邻接矩阵和邻接表是两种存储方式。这些东西看着简单,但后面所有的图算法——最短路径、社区发现、中心性分析——都建立在这个基础上。

下一节我们会用 Python 的 NetworkX 库把这些概念落地,写点能跑的代码。到时候你就知道,图论不是纸上谈兵,是真能解决实际问题的。


公众号:蓝海资料掘金营,微信deep3321