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

时间:2014-02-27 11:37:06

标签: functional-programming ocaml

在Java或其他命令式编程中,图表可以表示为matrixadjacent listadjacent list可能最受欢迎,因为它使用array时非常简洁方便。

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

map

替换数组
{p}在ocaml 99, graph中列出了4种方式:

edge-clause表格

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

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

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

图表术语

另一种方法是将整个图表表示为一个数据对象。根据图形定义为一对两组(节点和边),我们可以使用以下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)不存在。图形术语表格是我们的默认表示。您可能希望使用集而不是列表来定义类似的类型。

邻接列表表格

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

以人性化的形式

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

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

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

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

3 个答案:

答案 0 :(得分:7)

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

答案 1 :(得分:3)

需要考虑两件事:图表的表示,以及某些图算法中使用的中间数据结构。

我认为邻接列表表单是表示图形的最有效的内存方式。可以通过使用类型

的树或地图来改进一点
type Graph a = Map a [a]

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

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

答案 2 :(得分:0)

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

在函数式语言中也是如此。

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