6

我需要构建一个无向图。我不需要它做任何太花哨的事情,但理想情况下它会像这样工作:

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)

错误

当我做

结构 UDG = UndirectedGraphFn(结构
  类型节点 = int
  val compare = Int.compare
  val 格式 = Int.toString
结尾)

UDG.addEdge (UDG.empty,1,2)

我得到一个类型不匹配:

错误:运算符和操作数不一致 [字面量]
  运算符域:UDG.graph * ?.UDG.node * ?.UDG.node
  操作数:UDG.graph * int * int
  表达:
    UDG.addEdge (UDG.empty,1,2)
4

4 回答 4

4

好的,我不熟悉这种语言(请原谅我的无知):

我会简单地使用以下结构:

V.E1.E2.En+1
V2.E1.E2.En+1
Vn+1.E1.E2.En+1

所以基本上小数点前的第一个数字代表顶点,每个边都表示后面跟一个小数点(有点像 IP 地址)

这样:

替代文字

可以存储为:

1.2.5

2.1.5.3

3.2.4

4.3.5.6

5.1.2.4

6.4

然后在您的代码中,添加/删除边很简单,并且很容易解析(因为顶点始终是第一个数字)

于 2009-09-15T14:16:13.163 回答
4

有几种可能性,具有不同的优缺点,适用于图上的不同操作。 这个很好的介绍给出了使用邻接列表和邻接矩阵的背景和示例。

以无方向的方式使用它们涉及权衡(空间与速度)。本课程材料更详细地介绍了邻接列表样式,并提供了一些关于在无向使用中使用的可能更改的想法。

于 2009-09-08T23:17:26.767 回答
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 的。)

于 2009-09-08T23:26:14.083 回答
0

图及其邻接表

我们可以将图表示为列表的列表,我们称这种数据结构为:邻接列表。

于 2018-10-19T11:36:31.173 回答