首页 文章

OCaml中最常用的数据结构代表图表是什么?

提问于
浏览
9

在Java或其他命令式编程中,图形可以表示为 matrixadjacent list . adjacent list 可能是最受欢迎的,因为它使用 array 时非常紧凑和方便 .

在函数式编程中,我们通常不使用 mutable array . 那么通常我们如何在OCaml或其他函数式编程中呈现图形?

map 替换数组?


ocaml 99, graph中列出了4种方式:

edge-clause form

一种方法是列出所有边,边是一对节点 . 在这种形式中,相反描绘的图表表示为以下表达式:

['h', 'g';  'k', 'f';  'f', 'b';  'f', 'c';  'c', 'b']

我们称之为edge-clause形式 . 显然,无法表示孤立的节点 .

graph-term form

另一种方法是将整个图表表示为一个数据对象 . 根据图形的定义,作为一对两组(节点和边),我们可以使用以下OCaml类型:

type 'a graph_term = { nodes : 'a list;  edges : ('a * 'a) list }

然后,上面的示例图表由:

let example_graph =
{ nodes = ['b'; 'c'; 'd'; 'f'; 'g'; 'h'; 'k'];
  edges = ['h', 'g';  'k', 'f';  'f', 'b';  'f', 'c';  'c', 'b'] }

我们称之为图形术语形式 . 请注意,列表保持排序,它们确实是集合,没有重复的元素 . 每条边在边列表中只出现一次;即,从节点x到另一个节点y的边缘表示为(x,y),该对(y,x)不存在 . 图形术语表格是我们的默认表示 . 您可能希望使用集而不是列表来定义类似的类型 .

adjacency-list form

第三种表示方法是将与该节点相邻的一组节点与每个节点相关联 . 我们称之为邻接表格 .

human-friendly form

到目前为止我们介绍的表示非常适合自动处理,但它们的语法不是非常用户友好 . 手动输入术语既麻烦又容易出错 . 我们可以如下定义更紧凑和“人性化”的符号:图形(带有char标记的节点)由一串原子和X-Y类型的术语表示 . 原子代表孤立的节点,X-Y术语代表边缘 . 如果X显示为边的 endpoints ,则会自动将其定义为节点 . 我们的例子可以写成:

"b-c f-c g-h d f-b k-f h-g"

考虑到处理效率,我认为上述4种方法都不够好 .

对于 record type graph-term form ,没有有效的方法来定位节点(始终为 O(n) )并找到连接到节点的边 .

3 回答

  • 7

    有两点需要考虑:图表的表示和某些图算法中使用的中间数据结构 .

    我认为邻接列表形式是表示图形的最有效的内存方式 . 可以通过树或类型的 Map 来改进一点

    type Graph a = Map a [a]
    

    但是当你想运行像“强连接组件”或“拓扑排序”这样的算法时,那些算法很可能会使用可变数组来实现它 .

    注意,在像Haskell这样的语言中,ST monad使得有可能具有临时可变状态,即数组),而不是全局状态 . 使用它的功能仍然是整体纯粹的 .

  • 0

    您可能对OCamlGraph库(http://ocamlgraph.lri.fr)感兴趣,它提供了各种图形实现,包括持久性或可变性,以及一堆经典算法 .

  • 3

    在命令式语言中,图形表示的选择取决于您尝试解决的问题 .

    功能语言也是如此 .

    Ocamlgraph提供了足够的抽象,您可以编写独立于底层图表示的算法,当然算法的运行时仍然取决于实现 .

相关问题