ocaml图形遍历:如何保持访问的节点?
我正在尝试用DFS遍历一个图 但当我试图将访问的节点列表作为函数的参数传递时,我发现有一个问题 当我到达除前一个节点外没有连接节点的节点时,递归调用结束,有关访问节点的信息消失,从而陷入无限循环ocaml图形遍历:如何保持访问的节点?,ocaml,Ocaml,我正在尝试用DFS遍历一个图 但当我试图将访问的节点列表作为函数的参数传递时,我发现有一个问题 当我到达除前一个节点外没有连接节点的节点时,递归调用结束,有关访问节点的信息消失,从而陷入无限循环 除了使用命令式方法外,还有什么方法可以保存有关已访问节点的信息吗?一种方法是,您希望继续尝试图中其他可能的节点,而不是返回(例如,遍历树)。您可以有一些参数,不仅描述您访问过的节点,还描述您计划访问的节点。tovisit参数最初只是第一个节点。每次到达新节点时,都会将任何未访问的相邻节点(通过查看已访问
除了使用命令式方法外,还有什么方法可以保存有关已访问节点的信息吗?一种方法是,您希望继续尝试图中其他可能的节点,而不是返回(例如,遍历树)。您可以有一些参数,不仅描述您访问过的节点,还描述您计划访问的节点。tovisit参数最初只是第一个节点。每次到达新节点时,都会将任何未访问的相邻节点(通过查看已访问的节点集可以看出)添加到未访问的节点集中,并以这种方式递归继续。那么,DFS和BFS之间的区别在于您对要访问的节点列表的排序方式
在函数式编程中,很多时候,您不是从函数返回,而是调用函数来执行下一步操作。(这就是为什么尾部递归有时很重要。)看待这一点的一种方法是,您希望继续尝试图中其他可能的节点,而不是返回(例如,遍历树)。您可以有一些参数,不仅描述您访问过的节点,还描述您计划访问的节点。tovisit参数最初只是第一个节点。每次到达新节点时,都会将任何未访问的相邻节点(通过查看已访问的节点集可以看出)添加到未访问的节点集中,并以这种方式递归继续。那么,DFS和BFS之间的区别在于您对要访问的节点列表的排序方式
在函数式编程中,很多时候,您不是从函数返回,而是调用函数来执行下一步操作。(这就是为什么尾部递归有时很重要。)详细阐述Jeffrey的答案,您可以使用几种不同的样式。我在这里只给出我没有测试过的片段,所以可能会有小错误或大错误
module NodeSet = Set.Make(...)
let traverse action graph_root =
let visited = ref NodeSet.empty in
let rec loop node =
action node;
visited := NodeSet.add node !visited;
let handle child =
if not (NodeSet.mem child !visited)
then loop acc child in
List.iter handle (children node)
in loop graph_root
“访问”将命令式功能操作
应用于中的所有节点
图表acc
而不是
直接排序副作用。这将对应于使用
国家一号
let traverse action init_state graph_root =
let visited = ref NodeSet.empty in
let rec loop acc node =
let acc = action acc node in
visited := NodeSet.add node !visited;
let handle acc child =
if NodeSet.mem child !visited
then acc
else loop acc child in
List.fold_left handle acc (children node)
in loop init_state graph_root
let traverse action init_state graph_root =
let rec loop acc visited node =
let acc = action acc node in
let visited = NodeSet.add node visited in
let handle (acc, visited) child =
if NodeSet.mem child !visited
then (acc, visited)
else loop acc visited child in
List.fold_left handle (acc, visited) (children node)
in loop init_state NodeSet.empty graph_root
的方式更改为_visit
更新,将子节点添加到序列的末尾,而不是
而不是在开始时(这需要创建队列结构)
算法有效)详细阐述杰弗里的答案,你有几种不同的风格可供选择。我在这里只给出我没有测试过的片段,所以可能会有小错误或大错误
module NodeSet = Set.Make(...)
let traverse action graph_root =
let visited = ref NodeSet.empty in
let rec loop node =
action node;
visited := NodeSet.add node !visited;
let handle child =
if not (NodeSet.mem child !visited)
then loop acc child in
List.iter handle (children node)
in loop graph_root
“访问”将命令式功能操作
应用于中的所有节点
图表acc
而不是
直接排序副作用。这将对应于使用
国家一号
let traverse action init_state graph_root =
let visited = ref NodeSet.empty in
let rec loop acc node =
let acc = action acc node in
visited := NodeSet.add node !visited;
let handle acc child =
if NodeSet.mem child !visited
then acc
else loop acc child in
List.fold_left handle acc (children node)
in loop init_state graph_root
let traverse action init_state graph_root =
let rec loop acc visited node =
let acc = action acc node in
let visited = NodeSet.add node visited in
let handle (acc, visited) child =
if NodeSet.mem child !visited
then (acc, visited)
else loop acc visited child in
List.fold_left handle (acc, visited) (children node)
in loop init_state NodeSet.empty graph_root
的方式更改为_visit
更新,将子节点添加到序列的末尾,而不是
而不是在开始时(这需要创建队列结构)
算法有效)我不知道OCAML,但你能传递一个包含访问节点的集合吗?我是OCAML的新手,但OCAML是面向值的语言,所以一旦设置了变量的值,就没有办法改变值,除非使用命令式方式,这在函数式编程中不是首选方式……在Clojure(函数式)中,当你添加到一个集合时,你有一套新的。语言中有一些结构支持这一概念。我感谢你的评论。我会继续查找我不知道OCAML,但你能传递一个包含访问节点的集合吗?我是OCAML的新手,但OCAML是面向值的语言,所以一旦设置了变量的值,就没有办法更改值,除非使用命令式方式,这在函数式编程中不是首选方式……在Clojure(functional)中,当你添加到一个集合时,你会得到一个新的集合。语言中有一些结构支持这一概念。我感谢你的评论。我将继续查找4.,您是否应该过滤掉已访问的节点?如
let to_visit=children node@to_visit |>List.remove_if(flip NodeSet.mem visted)in…
well-spoted@unhammer,谢谢。我已经更改了代码,以检查在访问之前是否已经访问过,而不是