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;
}