我现在开始在graph
编写与data structure
相关的algorithms
和OCaml
。
我愿意尝试在OCaml中以功能方式编写它们,即避免使用array
,可变类型等。
但是,如果我使用list
编写所有内容,那么它会有效还是有意义?
答案 0 :(得分:4)
您不需要为所有内容使用列表。库中还有许多其他不可变数据结构,或者您可以定义自己的数据结构。您可以将图形视为从节点到后继列表的映射。我使用这种表示法在OCaml中编写了大量的图形处理代码,我对结果总是非常满意。
<强>更新强>
这是我正在谈论的代表性的草图。它假定您使用uniqe字符串标记节点。请注意(使用monniaux注释)使用后继列表可能更适合稀疏图形而不是密集图形。
type label = string
module GMap = Map.Make(struct type t = label let compare = compare end)
type 'a node = label * 'a * label list
type 'a graph = 'a node GMap.t
let empty = GMap.empty
let add (label: label) (contents: 'a) successors (graph: 'a graph) : 'a graph =
GMap.add label (label, contents, successors) graph
制作一个只包含长度为2的周期的图表:
# let g = add "a" () ["b"] (add "b" () ["a"] empty);;
val g : unit graph = <abstr>
答案 1 :(得分:4)
这完全取决于您希望实现的算法类型以及是否要考虑稀疏或密集图。密集图通常由矩阵表示(顺便说一句,它可以保持不变并在功能上使用)。
如果您需要具有O(1)更新的数组(例如用于标记节点),您仍然可以通过使用将数组呈现为可更新结构的包装器库以功能方式使用它们,每次都给出一个新数组。诀窍是通过将可变数组保持为“head”版本并将过去版本保持为“head”的增量来实现这些更新。这样就可以将所有必要的问题保存在一个模块中,至少在语义上呈现一个功能界面。
如果您有稀疏图表,通常会谈论“邻接列表”。我认为使用它们是个坏主意,除非图形非常稀疏(节点具有小程度,绝对值),因为它们具有O(n)访问权限。我认为二元树la Set
更适合,因为它们允许在O(log n)中进行测试。