我需要执行一个检查,是否在应用程序的性能至关重要的部分中以前已经看到过长值和整数值的组合。这两个值都可能变得非常大,至少在某些情况下,长整型将使用大于MAX_INT的值。
当前,我有一个非常简单的实现,使用Set<Pair<Integer, Long>>
,但是这将需要太多分配,因为即使对象已经在集合中,类似seen.add(Pair.of(i, l))
的东西也会添加/检查是否存在为每个呼叫分配配对。
在Java中(没有像Guava,Trove或Apache Commons这样的库)中,有没有更好的方法来以最小的分配和良好的O(?)
来执行此检查?
两个整数很容易,因为我可以在Set中将它们组合成一个long,但是这里不能避免这个long。
有什么建议吗?
答案 0 :(得分:1)
如何创建一个包含两个原语的类呢?在64位JVM中,仅将24 bytes
和Integer
的标头丢掉至少Long
。
在这种情况下,您正在寻找Pairing Function,或从2个数字中生成一个唯一的数字。维基百科页面上有一个很好的例子(简单),说明了这种可能性。
答案 1 :(得分:1)
这里有两种可能性。
以下两项建议中的一件事是将一堆成对的三元组int
存储在int[]
中。第一个int
是int
,接下来的两个int
是long
的上半部分和下半部分。
如果您不介意以33%的空间不足来换取寻址速度优势,则可以改用long[]
并将int
和long
存储在单独的索引中
您永远不会调用equals
方法。您只需将三个int
与其他三个int
进行比较,那将非常快。您永远不会调用compareTo
方法。您只需对这三个int
进行自定义词典顺序比较,这将非常快。
如果最终要考虑内存使用情况,则可以使用int[][]
或ArrayList<int[]>
创建B * 树。 B * 树相对较快且相当紧凑。
还有其他类型的B树可能更适合您的特定用例。
您还可以使用自定义的快速计算的哈希函数实现自定义哈希集(也许对int
和long
的上下半部分进行异或运算,这将非常快)而不是依靠hashCode
方法。
您将必须弄清楚如何实现int[]
存储桶以最适合您的应用程序的性能。例如,如何将自定义哈希码转换为存储桶编号?当存储桶中的元素过多时,是否要重新存储所有内容?依此类推。
答案 2 :(得分:0)
怎么样
class Pair {
int v1;
long v2;
@Override
public boolean equals(Object o) {
return v1 == ((Pair) o).v1 && v2 == ((Pair) o).v2;
}
@Override
public int hashCode() {
return 31 * (31 + Integer.hashCode(v1)) + Long.hashCode(v2);
}
}
class Store {
// initial capacity should be tweaked
private static final Set<Pair> store = new HashSet<>(100*1024);
private static final ThreadLocal<Pair> threadPairUsedForContains = new ThreadLocal<>();
void init() { // each thread has to call init() first
threadPairUsedForContains.set(new Pair());
}
boolean contains(int v1, long v2) { // zero allocation contains()
Pair pair = threadPairUsedForContains.get();
pair.v1 = v1;
pair.v2 = v2;
return store.contains(pair);
}
void add(int v1, long v2) {
Pair pair = new Pair();
pair.v1 = v1;
pair.v2 = v2;
store.add(pair);
}
}