Scala中的图形遍历

Mic*_*ael 5 scala traversal graph immutability

我知道的图遍历(DFS和BFS)实现使用一组可变的"访问"顶点.您将如何仅使用不可变数据结构来实现它们?

我看到了这个问题.现在我想知道是否还有其他解决方案

Phi*_*ppe 8

这是一种方法:

def traverse[A](graph : Map[A,Set[A]], toVisit : Seq[A], visited : Set[A]) : Seq[A] = {
  if(toVisit.isEmpty) {
    Seq.empty
  } else {
    val next = toVisit.head
    val succ = (graph(next) -- visited -- toVisit).toSeq
    // DFS :
    // next +: traverse(graph, succ ++ toVisit.tail, visited + next)
    // BFS :
    next +: traverse(graph, toVisit.tail ++ succ, visited + next)
  }
}

def traverseFrom[A](graph : Map[A,Set[A]], initial : A) =
  traverse(graph, Seq(initial), Set.empty)
Run Code Online (Sandbox Code Playgroud)

诀窍就是传递要访问的节点列表(这对应于命令式算法中的堆栈或队列)以及访问状态集.

如果你担心每次递归调用都会增加调用堆栈,你可以使用额外的参数使其尾递归:

@annotation.tailrec
def traverseTR[A](graph : Map[A,Set[A]], toVisit : Seq[A], visited : Set[A], accumulator : Seq[A]) : Seq[A] = {
  if(toVisit.isEmpty) {
    accumulator
  } else {
    val next = toVisit.head
    val succ = (graph(next) -- visited -- toVisit).toSeq
    // DFS :
    //traverseTR(graph, succ ++ toVisit.tail, visited + next, accumulator :+ next)
    // BFS :
    traverseTR(graph, toVisit.tail ++ succ, visited + next, accumulator :+ next)
  }
}

def traverseFrom[A](graph : Map[A,Set[A]], initial : A) =
  traverseTR(graph, Seq(initial), Set.empty, Seq.empty)
Run Code Online (Sandbox Code Playgroud)

这将为您提供一个高效的版本,就像您使用while循环编写它一样.