I've just started to learn Scala and decided to implement small graph library to train.
Here is the basic version, that describes graph and nodes structure and also provides implementation of DFS
to find some path from one node to other.
class Graph[A] {
var nodes = Set.empty[Node[A]]
def addNode(n: Node[A]) = nodes = nodes + n
def DFS(from: Node[A], to: Node[A]): List[Node[A]] = {
var visited = Set.empty[Node[A]]
@tailrec
def _DFS(from: Node[A], to: Node[A], path: List[Node[A]]): List[Node[A]] = {
visited = visited + from
if (from.equals(to)) path
else {
from.outgoing.find(n => !visited.contains(n)) match {
case Some(n) => _DFS(n, to, n :: path)
case None => path match {
case n :: Nil => List.empty[Node[A]]
case _ :: n :: ns => _DFS(n, to, n :: ns)
}
}
}
}
_DFS(from, to, List(from)).reverse
}
}
class Node[A](val i: A) {
var incoming = Set.empty[Node[A]]
var outgoing = Set.empty[Node[A]]
def addIncoming(n: Node[A]) = incoming = incoming + n
def addOutgoing(n: Node[A]) = outgoing = outgoing + n
}
I'm actively writing code in Java, so my primary goal is to not write Java code in Scala syntax. Hence, first and main question is: does my code looks like typical Scala code? If not, what should I change?
Next thing bothering me, is that my Node
is too loosely coupled with Graph
. I could invoke DFS only on instance of Graph
, but apart from this, I don't really use Graph
abstraction: I could just create instances of Node
and link them.
That leads me to another problem. Suppose now I want to define weighted graph. For Graph
itself I could define Weighted
trait, but then I need to replace inner Node
with NodeWithWeightedEdges
, and I don't understand how.