Skip to content

图存储调研报告

版本: v0.1.0 | 状态: 参考 | 日期: 2026-05-07


图是一种重要的数据结构,用于表示对象之间的关系。选择合适的图存储方式对算法性能和内存效率至关重要。本报告系统调研了 8 种主流的图数据存储方式。


存储方式空间复杂度邻居查询边存在查询增删操作缓存友好
邻接表O(V+E)O(k)O(k)O(1)🟡 一般
邻接矩阵O(V²)O(V)O(1)O(1)✅ 好
CSRO(V+E)O(k)O(log k)❌ 只读✅✅ 极好
CSCO(V+E)O(k)O(log k)❌ 只读✅✅ 极好
边集数组O(E)O(E)O(E)O(1)🟡 一般

特性:
空间: O(V+E) 查询边: O(deg(v))
添加边: O(1) 删除边: O(deg(v))
遍历邻居: O(deg(v)) 内存: 链表/数组
优点缺点
空间高效,适合稀疏图边存在查询慢 O(k)
邻居遍历灵活删除边需查找
动态增删支持好缓存不友好

实现 (mbtgraph: DirectedAdjList):

  • adj: Array[Array[(NodeId, Double)]]
  • 整型 ID 索引,支持动态扩容
特性:
空间: O(V²) 查询边: O(1)
添加边: O(1) 删除边: O(1)
遍历邻居: O(V) 内存: 连续 2D 数组
优点缺点
边存在查询 O(1) 常数空间 O(V²) 巨大
简单直观遍历邻居 O(V) 浪费
适合稠密图稀疏图 90%+ 空间浪费

实现 (mbtgraph: DirectedMatrix):

  • matrix: Array[Array[Double]]
  • 无向图仅存储上三角,节省 50%
特性:
空间: O(V+E) 查询边: O(log deg(v))
构建: O(E+V) 删除边: ❌ 只读
遍历邻居: O(deg(v)) 内存: 3 个连续数组
优点缺点
缓存友好连续内存只读不可修改
空间高效构建成本高
支持批量查询入边查询需 CSC

实现 (mbtgraph: CSRGraph):

  • row_ptr: Array[Int] — 行偏移
  • col_idx: Array[Int] — 列索引
  • values: Array[Double] — 边权重

CSR 的转置版本,优化入边查询。

  • 入边查询 O(deg(v)) — 邻接表需 O(V) 全扫描
  • 与 CSR 共享相同底层结构
特性:
空间: O(E) 查询边: O(E)
添加边: O(1) 删除边: O(E)
遍历所有边: O(E) 排序: O(E log E)
优点缺点
最紧凑存储所有查询慢
排序方便(Kruskal 友好)不适合频繁查询
适合批处理无邻居概念

实现 (mbtgraph: EdgeListGraph):

  • edges: Array[(NodeId, NodeId, Double)]

名称有向/无向空间特点
DirectedAdjList有向O(V+E)默认推荐,通用
UndirectedAdjList无向O(V+E)半存储,节省 50%
DirectedMatrix有向O(V²)稠密小图 (V<1000)
UndirectedMatrix无向O(V²/2)上三角存储
EdgeListGraph有向O(E)Kruskal 友好
UndirectedEdgeListGraph无向O(E)无向边集
CSRGraph有向O(V+E)大规模静态图
CSCGraph有向O(V+E)入边密集查询

输入规模及场景
├─ 节点数 < 1000(稠密图)
│ └─ 邻接矩阵
├─ 节点数 10³ ~ 10⁵(通用稀疏图)
│ ├─ 需要修改?→ 是 → 邻接表
│ └─ 只读 → CSR
├─ 节点数 > 10⁵(大规模图)
│ ├─ 批处理 → CSR/CSC
│ └─ 入边查询 → CSC
└─ 特定场景
├─ Kruskal MST → EdgeList
└─ 无向图 → UndirectedAdjList