Julia中如何用Graphs.jl创建节点为自定义类型的SimpleDiGraph有向图
解决方案
底层原理说明
Graphs.jl 中的
SimpleGraph/SimpleDiGraph是为高性能设计的轻量图结构,节点默认仅支持从 1 开始的连续正整数,底层邻接表依赖连续整数做索引,本身不支持直接存储任意自定义类型作为节点。
方案1:原生Graphs.jl手动维护映射(无额外依赖)
自己维护双向映射表,将自定义实例和连续整数ID一一绑定,操作图时做转换即可,示例代码:
using Graphs # 自定义类型定义 abstract type Foo end mutable struct Bar <: Foo b::Bool end mutable struct Baz <: Foo b::Bool end # 初始化自定义节点实例 bar = Bar(true) baz = Baz(false) nodes = [bar, baz] # 维护双向映射关系 obj_to_id = Dict(obj => i for (i, obj) in enumerate(nodes)) id_to_obj = Dict(i => obj for (i, obj) in enumerate(nodes)) # 初始化和节点数匹配的有向图 g = SimpleDiGraph(length(nodes)) # 加边时先把自定义对象转成整数ID add_edge!(g, obj_to_id[bar], obj_to_id[baz]) # 验证:遍历边时转回自定义对象 for e in edges(g) u = id_to_obj[src(e)] v = id_to_obj[dst(e)] println("边: $u -> $v") end
方案2:使用MetaGraphs.jl原生支持自定义节点
MetaGraphs是Graphs.jl官方生态的元数据扩展包,支持给节点、边附加任意类型的元数据,还可直接配置自定义类型作为节点索引,无需手动维护映射:
using Graphs, MetaGraphs # 自定义类型定义同上 abstract type Foo end mutable struct Bar <: Foo b::Bool end mutable struct Baz <: Foo b::Bool end bar = Bar(true) baz = Baz(false) # 初始化元有向图,第二个参数为节点总数 g = MetaDiGraph(2) # 给节点绑定自定义实例 set_prop!(g, 1, :value, bar) set_prop!(g, 2, :value, baz) # 建立自定义实例到节点ID的索引,之后可直接用实例操作图 set_indexing_prop!(g, :value) # 直接用自定义实例加边 add_edge!(g, bar, baz, :value) # 验证 for e in edges(g) u = g[src(e), :value] v = g[dst(e), :value] println("边: $u -> $v") end
错误方案说明
你尝试用pointer_from_objref转整数的方法不可行,原因有两个:
SimpleDiGraph的节点ID必须是从1开始的连续正整数,指针转换得到的整数远大于你初始化的图的节点总数,因此加边直接返回失败- 指针本身不稳定,Julia GC运行时会移动对象内存地址,后续指针会失效,存在内存安全风险
内容的提问来源于stack exchange,提问作者user14717
相关产品推荐
相关产品推荐

