这个深度优先搜索实现现在是尾递归的吗?
Is this Depth First Search implementation tail recursive now?
我有这个功能来遍历图形:
private def dfs(current: RCell, rCellsMovedWithEdges: Vector[RCell], acc: Vector[RCell] = Vector()): Vector[RCell] = {
current.edges.foldLeft(acc) {
(results, next) =>
if (results.contains(rCellsMovedWithEdges(next))) results
else dfs(rCellsMovedWithEdges(next), rCellsMovedWithEdges, results :+ current)
} :+ current
}
非常好,但我担心末尾的“:+ current”会使它成为非尾递归。
我改成了这样:
private def dfs(current: RCell, rCellsMovedWithEdges: Vector[RCell]): Vector[RCell] = {
@annotation.tailrec
def go(current: RCell, rCellsMovedWithEdges: Vector[RCell], acc: Vector[RCell] = Vector()): Vector[RCell] = {
current.edges.foldLeft(acc) {
(results, next) =>
if (results.contains(rCellsMovedWithEdges(next))) results
else go(rCellsMovedWithEdges(next), rCellsMovedWithEdges, results :+ current)
}
}
go(current, rCellsMovedWithEdges) :+ current
}
但是编译器说递归调用不在尾部位置。
leftfold 是否已经是尾递归了?
如果没有,是否有其他方法可以满足我的要求?
它不是尾递归,因为最后一次调用不是go
,而是foldLeft
。它不可能是相互尾递归的,因为 foldLeft
多次调用 go
。很难使 DFS 尾部递归,因为递归算法在很大程度上依赖于调用堆栈来跟踪您在树中的位置。如果你能保证你的树很浅,我建议不要打扰。否则,您将需要传递一个显式堆栈(List
是一个不错的选择)并完全重写您的代码。
如果您想以尾递归方式实现 DFS,您必须手动管理堆栈:
def dfs(start: RCell, rCellsMovedWithEdges: Vector[RCell]): Vector[RCell] = {
@annotation.tailrec
def go(stack: List[RCell], visited: Set[RCell], acc: Vector[RCell]): Vector[RCell] = stack match {
case Nil => acc
case head :: rest => {
if (visited.contains(head)) {
go(rest, visited, acc)
} else {
val expanded = head.edges.map(rCellsMovedWithEdges)
val unvisited = expanded.filterNot(visited.contains)
go(unvisited ++ rest, visited + head, acc :+ head)
}
}
}
go(List(start), Set.empty, Vector.empty)
}
奖励:将 unvisited ++ rest
更改为 rest ++ unvisited
,您将获得 BFS。
我有这个功能来遍历图形:
private def dfs(current: RCell, rCellsMovedWithEdges: Vector[RCell], acc: Vector[RCell] = Vector()): Vector[RCell] = {
current.edges.foldLeft(acc) {
(results, next) =>
if (results.contains(rCellsMovedWithEdges(next))) results
else dfs(rCellsMovedWithEdges(next), rCellsMovedWithEdges, results :+ current)
} :+ current
}
非常好,但我担心末尾的“:+ current”会使它成为非尾递归。
我改成了这样:
private def dfs(current: RCell, rCellsMovedWithEdges: Vector[RCell]): Vector[RCell] = {
@annotation.tailrec
def go(current: RCell, rCellsMovedWithEdges: Vector[RCell], acc: Vector[RCell] = Vector()): Vector[RCell] = {
current.edges.foldLeft(acc) {
(results, next) =>
if (results.contains(rCellsMovedWithEdges(next))) results
else go(rCellsMovedWithEdges(next), rCellsMovedWithEdges, results :+ current)
}
}
go(current, rCellsMovedWithEdges) :+ current
}
但是编译器说递归调用不在尾部位置。
leftfold 是否已经是尾递归了?
如果没有,是否有其他方法可以满足我的要求?
它不是尾递归,因为最后一次调用不是go
,而是foldLeft
。它不可能是相互尾递归的,因为 foldLeft
多次调用 go
。很难使 DFS 尾部递归,因为递归算法在很大程度上依赖于调用堆栈来跟踪您在树中的位置。如果你能保证你的树很浅,我建议不要打扰。否则,您将需要传递一个显式堆栈(List
是一个不错的选择)并完全重写您的代码。
如果您想以尾递归方式实现 DFS,您必须手动管理堆栈:
def dfs(start: RCell, rCellsMovedWithEdges: Vector[RCell]): Vector[RCell] = {
@annotation.tailrec
def go(stack: List[RCell], visited: Set[RCell], acc: Vector[RCell]): Vector[RCell] = stack match {
case Nil => acc
case head :: rest => {
if (visited.contains(head)) {
go(rest, visited, acc)
} else {
val expanded = head.edges.map(rCellsMovedWithEdges)
val unvisited = expanded.filterNot(visited.contains)
go(unvisited ++ rest, visited + head, acc :+ head)
}
}
}
go(List(start), Set.empty, Vector.empty)
}
奖励:将 unvisited ++ rest
更改为 rest ++ unvisited
,您将获得 BFS。