递归发生时,Scala StackOverflows

时间:2018-07-16 12:02:48

标签: scala graph-algorithm

嗨,我有一个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)

解决此问题的最佳方法是什么?

1 个答案:

答案 0 :(得分:1)

此代码有很多问题,但肯定不是尾递归。

尾部递归要求该函数仅执行一个递归调用,并且该调用必须是该函数中的最后一个动作。 (代码中可能有多个调用,但是对于代码中的任何给定路径,只能调用一个)

在您的代码中,对findCliques的递归调用在foreach循环内,因此可能多次调用,每个候选一次。仅此一个原因可能是堆栈溢出的原因。

您的@tailrec注释不起作用,因为它必须在函数定义之前,而不是在函数中间。

代码的其他问题包括格式错误,var的不必要使用,未使用的值(originalCandidates)和太多可变数据结构。