我们将字节数组中的知识存储为位。计算设置位数非常慢。欢迎任何改进算法的建议:
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,这太多了!
答案 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?
如果我的理解错误,请纠正我
由于 维诺德