嗨,我有一个BronKerbosch算法,用于检测使用Scala实现的社区。它的数据集包含超过100000个节点。当我运行代码时,它给出一个错误,指出stackoverflows。我也添加了@tailrec注释。在下面,我添加了代码以及错误
import org.apache.spark.SparkContext
import org.apache.spark.graphx.Graph.graphToGraphOps
import org.slf4j.{Logger, LoggerFactory}
import scala.annotation.tailrec
import scala.collection.mutable.{ArrayBuffer, Set => MutableSet}
import scala.reflect.ClassTag
class BronKerbosch[VD: ClassTag, ED: ClassTag](sc: SparkContext,
inputGraph: Graph[VD, ED]) {
private val logger: Logger =
LoggerFactory.getLogger(classOf[BronKerbosch[VD, ED]]);
private val sparkContext: SparkContext = sc;
private var graph: Graph[VD, ED] = inputGraph;
private var neighbourVerticesMap =
graph.collectNeighborIds(EdgeDirection.Either)
.collect().map(vertex => (vertex._1.asInstanceOf[Long], vertex._2))
.toMap;
def runAlgorithm = {
logger.info("Starting BronKerbosch Algorithm");
var potentialClique = Array[Long]()
var candidates = graph.vertices.map(vertex =>
vertex._1.asInstanceOf[Long]).collect().to[ArrayBuffer];
var alreadyFound = ArrayBuffer[Long]();
var cliques = ArrayBuffer[Array[Long]]()
findCliques(potentialClique, candidates, alreadyFound, cliques);
cliques;
}
private def findCliques(potentialClique: Array[Long],candidates: ArrayBuffer[Long], alreadyFound: ArrayBuffer[Long],cliques: ArrayBuffer[Array[Long]]): Unit = {
if (candidates.isEmpty && alreadyFound.isEmpty) {
cliques.append(potentialClique)
}
@tailrec
var originalCandidates = candidates
candidates.foreach { candidateVertex =>
{
var neighbourVertices = neighbourVerticesMap.getOrElse(candidateVertex, Array[Long]())
findCliques((potentialClique :+ candidateVertex).distinct,candidates.intersect(neighbourVertices),alreadyFound.intersect(neighbourVertices), cliques)
}
}
}
}
下面是错误
Exception in thread "main" java.lang.StackOverflowError
at
scala.collection.mutable.HashTable$class.findEntry(HashTable.scala:132)
at scala.collection.mutable.HashMap.findEntry(HashMap.scala:40)
at scala.collection.mutable.HashMap.apply(HashMap.scala:64)
at scala.collection.SeqLike$$anonfun$occCounts$1.apply(SeqLike.scala:481)
at scala.collection.SeqLike$$anonfun$occCounts$1.apply(SeqLike.scala:481)
at scala.collection.IndexedSeqOptimized$class.foreach(IndexedSeqOptimized.scala:33)
at scala.collection.mutable.WrappedArray.foreach(WrappedArray.scala:35)
at scala.collection.SeqLike$class.occCounts(SeqLike.scala:481)
at scala.collection.SeqLike$class.intersect(SeqLike.scala:469)
at scala.collection.AbstractSeq.intersect(Seq.scala:41)
at com.creative.graphx.BronKerbosch$$anonfun$com$creative$graphx$BronKerbosch$$findCliques$1.apply$mcVJ$sp(BronKerbosch.scala:57)
at com.creative.graphx.BronKerbosch$$anonfun$com$creative$graphx$BronKerbosch$$findCliques$1.apply(BronKerbosch.scala:53)
at com.creative.graphx.BronKerbosch$$anonfun$com$creative$graphx$BronKerbosch$$findCliques$1.apply(BronKerbosch.scala:53)
at scala.collection.mutable.ResizableArray$class.foreach(ResizableArray.scala:59)
at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:48)
at com.creative.graphx.BronKerbosch.com$creative$graphx$BronKerbosch$$findCliques(BronKerbosch.scala:53)
at com.creative.graphx.BronKerbosch$$anonfun$com$creative$graphx$BronKerbosch$$findCliques$1.apply$mcVJ$sp(BronKerbosch.scala:57)
at com.creative.graphx.BronKerbosch$$anonfun$com$creative$graphx$BronKerbosch$$findCliques$1.apply(BronKerbosch.scala:53)
at com.creative.graphx.BronKerbosch$$anonfun$com$creative$graphx$BronKerbosch$$findCliques$1.apply(BronKerbosch.scala:53)
at scala.collection.mutable.ResizableArray$class.foreach(ResizableArray.scala:59)
at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:48)
at com.creative.graphx.BronKerbosch.com$creative$graphx$BronKerbosch$$findCliques(BronKerbosch.scala:53)
at com.creative.graphx.BronKerbosch$$anonfun$com$creative$graphx$BronKerbosch$$findCliques$1.apply$mcVJ$sp(BronKerbosch.scala:57)
at com.creative.graphx.BronKerbosch$$anonfun$com$creative$graphx$BronKerbosch$$findCliques$1.apply(BronKerbosch.scala:53)
at com.creative.graphx.BronKerbosch$$anonfun$com$creative$graphx$BronKerbosch$$findCliques$1.apply(BronKerbosch.scala:53)
at scala.collection.mutable.ResizableArray$class.foreach(ResizableArray.scala:59)
at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:48)
at com.creative.graphx.BronKerbosch.com$creative$graphx$BronKerbosch$$findCliques(BronKerbosch.scala:53)
解决此问题的最佳方法是什么?
答案 0 :(得分:1)
此代码有很多问题,但肯定不是尾递归。
尾部递归要求该函数仅执行一个递归调用,并且该调用必须是该函数中的最后一个动作。 (代码中可能有多个调用,但是对于代码中的任何给定路径,只能调用一个)
在您的代码中,对findCliques
的递归调用在foreach
循环内,因此可能多次调用,每个候选一次。仅此一个原因可能是堆栈溢出的原因。
您的@tailrec
注释不起作用,因为它必须在函数定义之前,而不是在函数中间。
代码的其他问题包括格式错误,var
的不必要使用,未使用的值(originalCandidates
)和太多可变数据结构。