我正在研究Ocaml,但我仍然是初学者,所以我不得不寻求一些帮助。
按照书中的说明,我创建了一个代表方向图的类型:
type 'a graph = Gr of ('a * 'a) list;;
let grafo1 = Gr [(1,2);(1,3);(1,4);(2,6);(3,5);(4,6);(6,5);(6,7);(5,4)];;
然后我创建了一个succ函数,它将一个节点作为输入,它给了我继承者作为输出:
let succ (Gr arcs) n=
let rec aux = function
[] -> []
| (x,y):: rest ->
if n = x then y::(aux rest)
else aux rest
in aux arcs;;
然后我使用succ函数来修改BFS函数,这个函数显示我是否存在2个节点之间的路径:
let bfs graph p start =
let rec search visited = function
[] -> raise Nodo_not_reachable
|n:: rest ->
if List.mem n visited
then search visited rest
else if p n then n
else search (n::visited) (rest @ (succ graph n))
in search [] [start];;
我使用此代码调用该函数:
bfs grafo1 (function x -> x=7) 1;;
如果节点1和节点7之间存在路径,则该函数将为true。 现在,我想做同样的事情但是有一个加权图,所以我创建了一个新类型,一个列表,其中每个元素由3个数字组成,而不是2 :(节点开始 - 边缘 - 节点到达):
type 'b graph_w = Grw of ('b * 'b * 'b) list;;
let grafo2 = Grw [(1,3,2);(1,1,5);(2,2,3);(5,5,3);(5,4,6);(3,1,6);(3,7,4);(6,2,7);(4,4,6)];;
所以,我修改了我之前的功能,使其适应这种类型:
let succ_w (Grw arcs) n=
let rec aux = function
[]-> []
| (x,y,z)::rest ->
if n=x then z::(aux rest)
else aux rest
in aux arcs;;
let bfs_w graph_w p start =
let rec search visited = function
[] -> raise Nodo_non_raggiungibile
|n:: rest ->
if find n visited
then search visited rest
else if p n then n
else search (n::visited) (rest @ (succ_w graph_w n))
in search [] [start];;
(因为我不能在这个新类型上使用List.mem,我声明了一个名为find的函数,如果列表中包含元素(x,y,z),则将其作为输出为true):
let rec find (x,y,z) = function
[] -> false
| (v,c,p)::rest -> if (x=v) then true else find (x,y,z) rest;;
find (2,3,1) [(2,2,3);(4,5,6);(8,9,0)];;
现在有点问题,有人可以告诉我如何使用新图表类型调用我的bfs_w函数? 使用
bfs_w grafo2 (function x -> x=7) 1;;
我收到以下错误:
This expression has type int graph_w but an expression was expected of type ('a * 'b * 'c) graph_w
/ -------------------------------- /
好的,现在函数正常工作thx ^^,但还有另一个问题:因为我想用bfs解决最长的路径问题(给定一个起始节点和一个停止节点,如果存在节点之间的路径,则说明为true一个最小权重k)我必须在我的函数上实现(x,y,z)格式,所以我尝试了这样的事情:(与你建议的功能相同,但用(x,y,z)代替n:< / p>
let bfs_w2 graph_w start stop =
let rec search visited = function
| [] -> raise Node_not_Reachable
| (v,c,p) :: rest ->
if (find (v,c,p) visited) then search visited rest
else if v = stop then true
else search ((v,c,p)::visited) (rest @ (succ_w graph_w (v,c,p))) in
search [] [start];;
当我声明函数时:
bfs_w2 grafo2 1 4;;
或
bfs_w2 grafo2 (function x -> x=4) 1;;
我在“grafo2”上遇到了同样的错误:
This expression has type int graph_w
但是表达式需要类型('a *'b *'c)graph_w
我无法理解问题出在哪里,这个功能几乎与你建议的功能相同。
ps:我甚至试过这个,但我遇到了同样的结果:
let bfs_w2 graph_w p start =
let rec search visited = function
| [] -> raise Nodo_not_reachable
| (x,y,z) :: rest ->
if (List.mem (x,y,z) visited) then search visited rest
else if p (x,y,z) then (x,y,z)
else search ((x,y,z)::visited) (rest @ (succ_w graph_w (x,y,z))) in
search [] [start];;
答案 0 :(得分:1)
首先让我定义你的图形模型,这样我们就可以说同一种语言。您正在使用边缘列表来表示图表。对于'a graph
类型的图表,我们会说'a
是node
,而'a * 'a = node * node
是边缘。因此图表本身表示为edge list
。要表示加权图表,请使用标有权重的边缘,以便edge
现在键入node * weight * node
,其中weight
的类型为int
。
现在,让我们解决您的问题。如果您仔细查看bfs
实施,您会注意到,visited
的类型为node list
(即int list
),而非edge list
。并且您将谓词应用于node
类型的值,而不是边缘。
您的bfs_w
函数也应该如此。但是在这里,您出于某种原因,决定将{@ 1}}列表中的边缘存储起来,并使用您自己的visited
函数,而不是find
,这完全适用于此处。
List.mem
此实现将具有正确的类型,期望用户谓词接受类型为let bfs_w graph_w p start =
let rec search visited = function
| [] -> raise Not_found
| n :: rest ->
if List.mem n visited
then search visited rest
else if p n then n
else search (n::visited) (rest @ (succ_w graph_w n)) in
search [] [start]
的值。