我想使用邻接列表来表示图形结构,我不需要对边缘进行加权。
我想练习简单的练习,比如寻找一个循环,BFS,DFS,添加删除边缘......没什么特别的。 (我也可以用Hashtables做,但我需要更多List
练习)
type 'a dgraph = DG of ('a * 'a list) list
我的问题是:
我不想从头开始拍摄自己并从一开始就制作设计不佳的type
,这将导致更复杂的实施。
示例:
let g =
DG (
[
('a', ['c'; 'd']);
('c', ['d']);
('b', ['a'; 'e']);
]
)
注意:
我没有在http://ocaml.org/learn/tutorials/99problems.html#Graphs找到邻接列表表示。
答案 0 :(得分:2)
这是图表的完美表示。您需要确保标签是唯一的。此外,标签和节点的其他可能内容之间没有区别。
使用此结构,从标签到带有标签的节点需要搜索外部列表。如果你的图表变大,这可能会花费太长时间。因此,您需要构建从标签到节点的辅助映射。我自己做了很多次。
另一种解决方案是使节点索引独立于节点内容。这也减少了处理重复标签的难度。我正在研究图形问题,结构基本上是这样的:
type 'a mygraph = ('a * int list) array
'a
类型表示节点的内容,数组索引用于将它们链接在一起。
我还使用了一个使用哈希表而不是数组的结构。如果节点类型中有一些可用作索引的唯一标识符,则此方法很有效。 (或者您可以使用任意构造的索引。)哈希表结构的优点是更容易修改图形。
看起来您的数据结构应该是递归的,但(在我看来)这会混合图形和图形的表示。如果您希望您的数据结构实际上是图形而不仅仅是表示图形,那么它必须是递归的。像这样:
type 'a rgraph = RG of 'a * 'a rgraph list
这样的数据结构几乎不可能像OCaml这样的热切语言一起使用。在有周期时构造所需的值非常困难。
可以使用let rec
:
# let rec rg1 = RG (17, [rg1]);;
val rg1 : int rgraph = RG (17, [<cycle>])
但是,我个人从未见过使用这样结构的“真实世界”代码。请注意,let rec
的这种用法在OCaml手册中标记为语言扩展(第7.2节,值的递归定义)。
您可以通过使用引用使这样的数据结构更容易处理,这样的事情可能是:
type 'a rrgraph = RRG of 'a * 'a rrgraph list ref
然后您可以创建节点并在之后将它们链接在一起。我过去曾使用过这样的结构,但我觉得我失去了使用不可变数据的一些很好的保证。
# let node1 = RRG (7, ref []);;
val node1 : int rrgraph = RRG (7, {contents = []})
# let node2 = RRG (8, ref []);;
val node2 : int rrgraph = RRG (8, {contents = []})
# let RRG (_, links) = node1 in links := [node2];;
- : unit = ()
# let RRG (_, links) = node2 in links := [node1];;
- : unit = ()
# node1;;
- : int rrgraph = RRG (7, {contents = [RRG (8, {contents = [<cycle>]})]})
这样的表示的一个优点是您可以自由地创建新节点,而无需维护包含所有节点的中央表。垃圾收集器负责删除不再可访问的节点。