Java获取位集交集基数的最快方法
下面的函数获取两个Java获取位集交集基数的最快方法,java,intersection,bitset,cardinality,Java,Intersection,Bitset,Cardinality,下面的函数获取两个位集,复制第一个位集(不能重写),将该位集与第二个位集相交(按位AND),并返回结果的基数 public int getIntersectionSize(BitSet bits1, BitSet bits2) { BitSet copy = (BitSet) bits1.clone(); copy.and(bits2); return copy.cardinality(); } 我很感兴趣,如果这个代码可以加快?这个函数被调用了十亿次,所以即使是微秒级
位集
,复制第一个位集(不能重写),将该位集与第二个位集相交(按位AND),并返回结果的基数
public int getIntersectionSize(BitSet bits1, BitSet bits2) {
BitSet copy = (BitSet) bits1.clone();
copy.and(bits2);
return copy.cardinality();
}
我很感兴趣,如果这个代码可以加快?这个函数被调用了十亿次,所以即使是微秒级的速度也有意义,而且我对最快的代码很好奇。这里有一个替代版本,但我不确定它是否真的更快,这取决于
nextSetBit
public int getIntersectionsSize(BitSet bits1, BitSet bits2) {
int count = 0;
int i = bits1.nextSetBit(0);
int j = bits2.nextSetBit(0);
while (i >= 0 && j >= 0) {
if (i < j) {
i = bits1.nextSetBit(i + 1);
} else if (i > j) {
j = bits2.nextSetBit(j + 1);
} else {
count++;
i = bits1.nextSetBit(i + 1);
j = bits2.nextSetBit(j + 1);
}
}
return count;
}
public int getIntersectionSize(位集位s1、位集位s2){
整数计数=0;
int i=bits1.nextSetBit(0);
int j=bits2.nextSetBit(0);
而(i>=0&&j>=0){
if(ij){
j=bits2.nextSetBit(j+1);
}否则{
计数++;
i=位1.nextSetBit(i+1);
j=bits2.nextSetBit(j+1);
}
}
返回计数;
}
以上是可读版本,希望对编译器来说足够好,但我想您可以手动优化它:
public int getIntersectionsSize(BitSet bits1, BitSet bits2) {
int count = 0;
for (int i = bits1.nextSetBit(0), j = bits2.nextSetBit(0); i >= 0 && j >= 0; ) {
while (i < j) {
i = bits1.nextSetBit(i + 1);
if (i < 0)
return count;
}
if (i == j) {
count++;
i = bits1.nextSetBit(i + 1);
}
while (j < i) {
j = bits2.nextSetBit(j + 1);
if (j < 0)
return count;
}
if (i == j) {
count++;
j = bits2.nextSetBit(j + 1);
}
}
return count;
}
public int getIntersectionSize(位集位s1、位集位s2){
整数计数=0;
对于(int i=bits1.nextSetBit(0),j=bits2.nextSetBit(0);i>=0&&j>=0;){
而(i
如果要多次使用每个位集
,那么创建一个与每个位集
对应的长
数组是值得的。对于每个位集
:
long[] longs = bitset.toLongArray();
然后可以使用以下方法,从而避免创建克隆的位集的开销。(假设两个数组的长度相同)
int getIntersectionSize(长[]位s1,长[]位s2){
int-nBits=0;
对于(int i=0;i我最近一直在寻找解决方案,以下是我的想法:
int intersectionCardinality(final BitSet lhs, final BitSet rhs) {
int lhsNext;
int retVal = 0;
int rhsNext = 0;
while ((lhsNext = lhs.nextSetBit(rhsNext)) != -1 &&
(rhsNext = rhs.nextSetBit(lhsNext)) != -1) {
if (rhsNext == lhsNext) {
retVal++;
rhsNext++;
}
}
return retVal;
}
也许有人想在这里花点时间比较不同的解决方案并发布结果…一个想法:你可以尝试避免创建一个新的位集,而你只是扔掉了。需要更多信息:调用10亿次需要多长时间?你能改变你的算法不调用10亿次吗?我没有c检查位集内部,但可能一次完成所有操作,而不是执行和
然后执行基数
手动执行和
时尝试计算基数?@MateuszDymczyk看起来可以通过替换(a&b)来调整相交
方法来完成此操作!=0,带长.countBits(a&b)
和求和。但这需要访问单词,这是私有的。传统智慧建议,与最快的方式不同,您应该开发一种正确的方式来读取遗嘱并可维护。一旦您证明您的解决方案是一个性能瓶颈,您就可以深入研究执行速度优化通过基准测试(大多数情况下并非如此)。@BrandonMcHomery如果你想使用位集功能,我认为你的版本可能是你能获得的最好版本。以上可能有助于“稀疏”位集。如果您愿意,我可以删除它。@maraca这会慢一些,因为您是逐位进行的,内部位集
每字工作,所以和的操作数要小得多。@MateuszDymczyk是的,对于“稀疏”位集可能更好(大多数位为假)还是不?@maraca最有可能用于极稀疏集yes@BrandonMcHomery您可以尝试实现Andy Turner的想法,但是因为您需要在两个位集上调用toLongArray,所以您可以克隆它们,所以我想这也不会更快。
int intersectionCardinality(final BitSet lhs, final BitSet rhs) {
int lhsNext;
int retVal = 0;
int rhsNext = 0;
while ((lhsNext = lhs.nextSetBit(rhsNext)) != -1 &&
(rhsNext = rhs.nextSetBit(lhsNext)) != -1) {
if (rhsNext == lhsNext) {
retVal++;
rhsNext++;
}
}
return retVal;
}