Java 如何在没有内存溢出的情况下检出图形中的所有周期?
相邻列表中的图形示例:Java 如何在没有内存溢出的情况下检出图形中的所有周期?,java,scala,graph,Java,Scala,Graph,相邻列表中的图形示例: > (K01196,List(K00700, K01178, K01187, K00688)) > (K00844,List(K01835, K01810)) > (K00700,List(K00688)) > (K01178,List(K01196, K01187)) > (K00706,List(K00693, K01210, K00963, K00697, K16055)) > (K01810,List(K00844, K0183
> (K01196,List(K00700, K01178, K01187, K00688))
> (K00844,List(K01835, K01810))
> (K00700,List(K00688))
> (K01178,List(K01196, K01187))
> (K00706,List(K00693, K01210, K00963, K00697, K16055))
> (K01810,List(K00844, K01835))
> (K01193,List(K00844, K01210, K01187))
> (K00693,List(K01196, K00688, K00700))
> (K16055,List(K01194, K00693))
> (K01835,List(K00844, K00688, K01810, K00963))
> (K00963,List(K00688, K16055, K00693, K01835, K00697))
> (K00697,List(K16055, K00693))
> (K01187,List(K01178, K01210, K00844))
第二个例子(容易出现问题):
相邻列表是使用默认值list()生成的。可以使用以下函数加载边,它将返回相邻列表
def reader_AdjacentList(edgefile: String): Map[String, List[String]] = {
val sourcefile = Source.fromFile(edgefile)
val pat = """([A-Z]\w+),([A-Z]\w+)""".r
sourcefile.getLines.:\(Map[String, List[String]]().withDefaultValue(List()))((line, maps) =>
pat.findFirstMatchIn(line) match {
case Some(pat(from, to)) => if (maps.contains(from)) maps.updated(from, maps(from).+:(to).distinct)
else maps.+((from, List(to)))
case None => maps
})
}
下面的功能是检查给定开始节点和图形的所有循环:
def checkCycles(start: String, maps: Map[String, List[String]]): List[List[String]] = {
def explore(node: String, visits: List[String]): List[List[String]] = {
if (visits.contains(node)) List(visits.+:(node))
else {
if (maps(node).isEmpty) List()
else {
maps(node).flatMap(x => explore(x, visits.+:(node)))
}
}
}
explore(start, List())
}
为检出所有循环路径而运行的程序如下所示(adList
是开头相邻列表表示的图形):
此程序适用于其他一些图形示例,例如上面给出的第一个示例,但不适用于第二个示例,它给出了以下错误,尽管eclipse中的堆大小已设置为4G
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
有人知道这个程序出了什么问题,以及如何改进它吗?在我的计算机上运行完全正常,无需更改堆空间的任何设置。
循环的长度为818。我所做的唯一改变是,现在所有节点都是符号(因为我只是将您的员工复制到我的IDE中,这是使事情正常运行的最快方法),这一点都不重要
更新
由于第二个示例不容易复制和粘贴,我正在生成我自己的更大比例的示例,这是一个随机图,每个节点都有n
个节点和k
个边(删除自循环和重复边)
对于n=50
和k=4
,有124693个“周期”(如您所定义)。我还尝试了n=100
和k=10
,似乎要计算的路径太多了,因此程序不会在几分钟内终止,但不会引发内存异常。在示例映射中,某些节点(如K00688)没有键。。。因此,您可能需要添加映射。包含(节点)
检查。修复后,代码在我的计算机上完全正常工作,无需更改堆空间的任何设置。它将由默认值列表()处理。我刚刚编辑了这篇文章以包含这些信息。相邻列表是使用默认值生成的。它给出了java.util.NoSuchElementException:key not found:'K00688
在我的计算机上,而不是在缺少密钥时返回一个空集,这并不奇怪。。。您确定这就是您正在运行的代码吗?相邻的列表是通过折叠并以Map[String,list[String]]()开始创建的。withDefaultValue(list())。您所说的“所有周期”是什么意思?假设我们有一个由10个元素组成的完全连通的网络;那你就有大约10个!循环,这是相当多的。在你可以探索它们之前,很容易创造出足够的周期,不仅超过机器的内存容量,而且超过宇宙的年龄。@QiQi当然,但更好的是,我可以复制和粘贴,让事情顺利进行,而无需做任何其他事情……只需在这个程序上独立运行,与其他部分分离。第一个例子运行良好,@Kane,你是对的。但我将发布另一个容易出现问题的示例。您可以将边缘保存到一个文件中,然后使用我刚刚发布的函数将文件加载到相邻列表的映射中。我很感激你的努力,凯恩,你不必在这上面花太多时间。谢谢。我的计算机运行第二个示例时花了两分钟多的时间,出现了错误。@QiQi您的第二个示例正在运行。。。没有内存异常,但它只是不终止。我添加了一个计数器来动态打印到目前为止找到的路径数,它在几秒钟内增长到数百万条——这只是表明事情正在正常工作。
val cycles = adList.toList.flatMap(pair => checkCycles(pair._1, adList))
cycles.foreach(println)
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
val rand = new java.util.Random
val n = 50
val k = 4
val map = 0 until n map (i => {
i -> ((0 until k) map (_ => rand.nextInt(n)) filter (_ != i) groupBy(identity) map (_._1) toList)
}) toMap