算法的改进:在字节数组中计数设置位

时间:2013-02-15 12:16:16

标签: java bit-manipulation

我们将字节数组中的知识存储为位。计算设置位数非常慢。欢迎任何改进算法的建议:

public static int countSetBits(byte[] array) {
    int setBits = 0;

    if (array != null) {
        for (int byteIndex = 0; byteIndex < array.length; byteIndex++) {
            for (int bitIndex = 0; bitIndex < 7; bitIndex++) {
                if (getBit(bitIndex, array[byteIndex])) {
                    setBits++;
                }
            }
        }
    }
    return setBits;
}
public static boolean getBit(int index, final byte b) {
    byte t = setBit(index, (byte) 0);
    return (b & t) > 0;
}
public static byte setBit(int index, final byte b) {
    return (byte) ((1 << index) | b);
}

要计算长度为156'564的字节数组的位需要300 ms,这太多了!

5 个答案:

答案 0 :(得分:5)

尝试Integer.bitcount获取每个字节中设置的位数。如果您可以从byte数组切换到int数组,效率会更高。如果这不可能,您还可以为所有256个字节构建一个查找表,以快速查找计数,而不是迭代各个位。

如果它总是你感兴趣的整个数组的计数,你可以将数组包装在一个类中,只要数组发生变化,该数组就会将计数存储在一个单独的整数中。 (编辑:或者,确实如评论中所述,使用java.util.BitSet。)

答案 1 :(得分:2)

我会使用相同的全局循环,但不是在每个字节内循环,而是简单地使用大小为256的(预先计算的)数组将字节映射到它们的位数。这可能会非常有效。

如果你需要更高的速度,那么你应该单独保持计数并增加它并在设置位时递减它(但这对那些操作来说意味着很大的额外负担,所以我不确定它是否适用于你)。

另一个解决方案将基于BitSet implementation:它使用一个长数组(而不是字节数),以及它的计算方式:

658        int sum = 0;
659        for (int i = 0; i < wordsInUse; i++)
660            sum += Long.bitCount(words[i]);
661        return sum;

答案 2 :(得分:1)

我会用:

    byte[] yourByteArray = ...
    BitSet bitset = BitSet.valueOf(yourByteArray);  // java.util.BitSet
    int setBits = bitset.cardinality();

我不知道它是否更快,但我认为它会比你拥有的更快。让我知道吗?

您的方法看起来像

 public static int countSetBits(byte[] array) {
     return BitSet.valueOf(array).cardinality();
 }

你说:

  

我们将字节数组中的知识存储为位。

我建议使用BitSet。它为您提供了方便的方法,您似乎对位而不是字节感兴趣,因此与byte[]相比,它是更合适的数据类型。 (在内部使用long[])。

答案 3 :(得分:0)

到目前为止,最快的方法是计算位集,在&#34; parallel&#34;中,方法称为Hamming weight 据我所知,已在Integer.bitCount(int i)中实施。

答案 4 :(得分:-1)

根据我的不足,

1字节= 8位

因此,如果字节数组大小= n,则不是总位数= n * 8?

如果我的理解错误,请纠正我

由于 维诺德