私は関数型プログラミングをよりよく理解しようとしており、いくつかの古典的なグラフ アルゴリズムを実装することにしました。BFS ループを末尾再帰関数にラップすることで接続を実装しましたが、このコードは命令よりもはるかに優れているようには見えません。それをより適切に実装する方法はありますか (for
内包表記、モナドなどを使用)?
object Graph {
def apply(n: Int) = new Graph(n, Vector.fill(n)(List.empty[Int]))
}
class Graph private (val n: Int, val adj: IndexedSeq[List[Int]]) {
def addEdge(u: Int, v: Int) = {
new Graph(n, adj.updated(u, v :: adj(u)).updated(v, u :: adj(v)))
}
def connected = {
@tailrec
def connectedIter(q: Queue[Int], visited: Seq[Boolean]) : Boolean = {
if(q.isEmpty) visited.forall(x => x) else {
val (v, newq) = q.dequeue
val newVisited = visited.updated(v, true)
connectedIter(adj(v).foldLeft(newq){(acc, x) => if(visited(x)) acc else acc.enqueue(x)}, newVisited)
}
}
connectedIter(Queue[Int](0), IndexedSeq.fill(n)(false))
}
}
PS本質的に再帰的なDFSを使用すると、少し見栄えが良くなります
def reachableDfs(v: Int): Seq[Boolean] = reachableDfs(v, Vector.fill(n)(false))
private def reachableDfs(v: Int, visited: Seq[Boolean]) : Seq[Boolean] = {
val newV = visited.updated(v, true)
adj(v).filterNot{x => newV(x)}.foldLeft(newV){(acc, x) => reachableDfs(x, acc)}
}