最佳哈希集初始化(Scala | Java)

最佳哈希集初始化(Scala | Java),scala,optimization,hashset,Scala,Optimization,Hashset,我正在写一份人工智能来解决一个“难题”。试图将状态存储到哈希集会降低速度。在没有一组状态的情况下运行它会更快。我确信我的节点(状态存储)实现了equals和hashCode,测试表明HashSet不会添加重复的状态。我可能需要重新编写hashCode函数,但我相信会减慢速度的是HashSet的重新分级和调整大小 我尝试将初始容量设置为一个非常大的数字,但仍然非常缓慢: val initCapacity = java.lang.Math.pow(initialGrid.width*initial

我正在写一份人工智能来解决一个“难题”。试图将状态存储到
哈希集
会降低速度。在没有一组状态的情况下运行它会更快。我确信我的节点(状态存储)实现了equals和
hashCode
,测试表明
HashSet
不会添加重复的状态。我可能需要重新编写
hashCode
函数,但我相信会减慢速度的是
HashSet
的重新分级和调整大小

我尝试将初始容量设置为一个非常大的数字,但仍然非常缓慢:

 val initCapacity = java.lang.Math.pow(initialGrid.width*initialGrid.height,3).intValue()
 val frontier = new QuickQueue[Node](initCapacity)
以下是快速队列代码:

class QuickQueue[T](capacity: Int) {

val hashSet = new HashSet[T](capacity)
val queue = new Queue[T]
    //methods below
有关更多信息,请参见哈希函数。我将网格值以字节的形式存储在两个数组中,并使用元组进行访问:

override def hashCode(): Int = {
  var sum = Math.pow(grid.goalCoords._1, grid.goalCoords._2).toInt
  for (y <- 0 until grid.height) {
     for (x <- 0 until grid.width) {
        sum += Math.pow(grid((x, y)).doubleValue(), x.toDouble).toInt
     }
     sum += Math.pow(sum, y).toInt
  }
  return sum
}
覆盖def hashCode():Int={
var sum=Math.pow(grid.goalCoords.\u 1,grid.goalCoords.\u 2).toInt

对于(y好的,首先,请更换

override def hashCode(): Int =

因此,您不必每次需要访问哈希代码时都计算(
grid.height*grid.width
)浮点幂。这将大大加快速度

然后,除非您以某种方式依赖具有闭合哈希代码的闭合单元格,否则不要重新发明轮子。使用
scala.util.hashing.MurrushHash3.seqHash
或类似的方法来计算您的哈希。这将使您的哈希速度提高20倍左右(仍然保留延迟值)


现在,除非您有很多0x0网格,否则等待math.pow给出结果的时间将占绝大多数(并冒着一切变成双重的风险。正不确定性
0.0
,这取决于值的大小,这将产生哈希冲突,从而进一步降低速度)。

请注意,以下假设所有对象都是不可变的。这是使用哈希时明智的假设

此外,您还应该在应用优化之前评测代码(例如,使用JDK附带的免费jvisualvm)

fast的备忘
hashCode
计算哈希代码通常是一个瓶颈。通过对每个对象只计算一次哈希代码并存储结果,您可以将哈希代码计算的成本降至最低(在对象创建时计算一次),但会增加空间消耗(可能适中)。为此,将
def hashCode
转换为
lazy val
val

快速
等于

一旦消除了
hashCode
的成本,计算
equals
就成了一个问题。
equals
通常对于集合字段和深层结构来说特别昂贵


您可以通过实习来最小化
equals
的成本。这意味着您通过工厂方法获取类的新对象,工厂方法检查请求的新对象是否已经存在,如果已经存在,则返回对现有对象的引用。如果您断言此类型的每个对象都是以这种方式构造的,则您知道这里只有每个不同对象的一个实例,
equals
将等价于对象标识,这是一种廉价的参考比较(
eq
在Scala中).

hashCode
中调用了大量的
Math.pow
!您可能需要缓存哈希值。您的hashCode函数似乎太过计算密集。使用一些快速的方法,只需稍微修改一下就可以了。我建议使用不可变类来表示状态,并使用
val
来兑现哈希代码。此外,如果您将字节存储在标准库集合中,还可以直接使用它们提供的哈希函数。如果您确信大多数/每个对象的
hashCode
都会被调用,那么您就可以避免
lazy
开销。@ziggystar-这是正确的,但基本上是不相关的。
lazy val
占用的量可以忽略不计与散列集操作的其余部分相比,内存的挑战是避免内存值的过度保留,特别是当它们占用大量主存时。
override lazy val hashCode: Int =