我需要构建一个无向图。我不需要它做任何太花哨的事情,但理想情况下它会像这样工作:
structure UDG = UndirectedGraph
val g = UDG.empty
val g = UDG.addEdges(g, n1, [n2, n4, n7]) (* n1 is connected to n2, n4, and n7 *)
val g = UDG.addEdge(g, n2, n3)
UDG.connected(g, n2) (* returns [n1, n3] *)
SML / NJ中是否有良好的数据结构来建模这些关系?我应该自己动手吗?
我已经开始尝试滚动自己,但是当我尝试测试它时,我遇到了类型不匹配错误。我对SML结构和仿函数的经验非常基础,所以我认为我做的事情显然是错误的。我如何让它工作?另外,你能帮助我做一个'a graph
吗?从语义上看,这似乎更有意义。
signature ORD_NODE =
sig
type node
val compare : node * node -> order
val format : node -> string
end
signature GRAPH =
sig
structure Node : ORD_NODE
type graph
val empty : graph
(* val addEdge : graph * Node.node * Node.node -> graph
* addEdge (g, x, y) => g with an edge added from x to y. *)
val addEdge : graph * Node.node * Node.node -> graph
val format : graph -> string
end
functor UndirectedGraphFn (Node : ORD_NODE) :> GRAPH =
struct
structure Node = Node
structure Key = struct
type ord_key = Node.node
val compare = Node.compare
end
structure Map = BinaryMapFn(Key)
type graph = Node.node list Map.map (* Adjacency list *)
val empty = Map.empty
fun addEdge (g, x, y) = (* snip *)
fun format g = (* snip *)
end
structure UDG = UndirectedGraphFn(struct
type node = int
val compare = Int.compare
val format = Int.toString
end)
当我这样做时
structure UDG = UndirectedGraphFn(struct type node = int val compare = Int.compare val format = Int.toString end) UDG.addEdge (UDG.empty,1,2)
我的类型不匹配:
Error: operator and operand don't agree [literal] operator domain: UDG.graph * ?.UDG.node * ?.UDG.node operand: UDG.graph * int * int in expression: UDG.addEdge (UDG.empty,1,2)
答案 0 :(得分:4)
有几种可能性,不同的优点和缺点适合图表上的不同操作。 This nice intro给出了使用Adjacency Lists和Adjacency Matrices的背景和示例。
以无向的方式使用它们涉及权衡(空间与速度)。 this course material详细介绍了邻接列表的样式,并提供了一些关于在无向使用中使用的可能变更的想法。
答案 1 :(得分:4)
好的我不熟悉这种语言(请原谅我的无知):
我只是使用以下结构:
V.E1.E2.En+1
V2.E1.E2.En+1
Vn+1.E1.E2.En+1
所以基本上小数点前的第一个数字代表Vertice,每个Edge代表一个小数点(有点像IP地址)
这样:
可以存储为:
1.2.5
2.1.5.3
3.2.4
4.3.5.6
5.1.2.4
6.4
然后在你的代码中,它简单地添加/删除边缘,并且很容易解析(因为顶点总是第一个数字)
答案 2 :(得分:1)
一个非常简单的方法是哈希表,密钥作为源节点,值作为连接节点列表。然后编写一个执行两个哈希表插入的add函数,一个用作(src,tgt),另一个用作(tgt,src)。
在ocaml:
let add n1 n2 =
let aux n1 n2 =
match Hashtbl.find_option tbl n1 with
| None -> Hashtbl.add tbl n1 [n2]
| Some nodes -> Hashtbl.replace tbl n1 (n2::nodes)
in
let _ = aux n1 n2 in
aux n2 n1
这将是一个有向图,只是你会在插入时添加两个方向。哈希表查找功能将充当您的connected
函数。
(实际上,在Ocaml哈希表中为密钥提供了多个值,因此您可以使用Hashtbl.find_all
函数并保存列表。但这是最容易转换为SML的。)
答案 3 :(得分:0)