如何在位集JAVA中左右移动位?
我有一个位数为100000的位集。我希望尽可能高效地将其向右和向左移动。我猜BitSet类中没有移位位的函数,所以我尝试使用如何在位集JAVA中左右移动位?,java,bit-manipulation,bit-shift,bitset,Java,Bit Manipulation,Bit Shift,Bitset,我有一个位数为100000的位集。我希望尽可能高效地将其向右和向左移动。我猜BitSet类中没有移位位的函数,所以我尝试使用toLongArray()将它们转换为长数组,但正如预期的那样,它会产生溢出 我发现的一个临时解决方案是将位集转换为biginger,然后将biginger移位,然后将biginger转换回位集,但这非常缓慢 因此,我的问题是: 有没有更好的方法来移位一个位集(移位我指的是左移位和右移位) 当我将位数大于64的位集转换为长数组时,数组中会出现负数。当位集只能表示1个数字的位
toLongArray()
将它们转换为长数组,但正如预期的那样,它会产生溢出
我发现的一个临时解决方案是将位集转换为biginger,然后将biginger移位,然后将biginger转换回位集,但这非常缓慢
因此,我的问题是:
toLongArray()
。如果我错了,请纠正我公共静态位集toBitSet(biginger val){
if(val.signum()<0)
抛出新的IllegalArgumentException(“负值:+val”);
返回BitSet.valueOf(反向(val.toByteArray());
}
静态字节[]反向(字节[]字节){
对于(int i=0;i
PS:我找到的所有答案都是关于位数的
当我将位数大于64的位集转换为长数组时,数组中会出现负数
负元素非常好,这只是使用长的所有64位的结果,因此包括符号位。只要你能预料到,这并不重要。基本上,它只是在打印带有签名的解释时看起来很奇怪,否则这不是一件坏事
因此,我尝试使用toLongArray()
将它们转换为长数组,但正如预期的那样,它会产生溢出
这是一个合理的实施策略,所以让我们来解决它。我猜你在没有处理“进位”的情况下单独移动了每个元素。左移位需要做的是将一个元素的顶部位放入下一个元素的底部位。对于右移来说,情况正好相反。例如,对于小于或等于63的n
(未测试)
静态位集移位触发器(位集位,int n){
long[]原始=位。toLongArray();
长进位=0;
对于(int i=raw.length-1;i>=0;i--){
长进位=原始进位[i]>>n)|进位;
进位=新进位;
}
返回BitSet.valueOf(原始);
}
如果n
可以是64或更大,则将整个元素移动到不同位置会带来额外的复杂性
向左移动会带来额外的复杂性,即结果集可能比输入更大(不是设置更多的位,而是物理上更大,需要更长的数组)。如果您需要尽可能有效的左移,可以使用列表来代替,例如,LinkedList
应该是最有效的移位数据结构,因为您可以通过在O(1)
@Robert yes中插入/删除元素来执行移位操作,但我还想执行and、or、xor等操作。比特集内置了对它们的支持,这就是我选择它的原因。为什么你认为获取负长值是个问题?如果可以使用长负值的所有64位,则只需使用长on位级别,不要试图将其解释为值。顺便说一句:查看位集的实现,您可以看到它在内部使用long[]
来存储位。因此,通过调用toLongArray()
您只需获得内部表示的副本。@Robert。这是一个问题,因为我认为应该只返回一个值。但正如您所说,内部实现使用long[]
,那么我想在溢出的情况下获得一个填充了-ve值的数组是有意义的。
static BitSet shiftRight(BitSet bits, int n) {
long[] raw = bits.toLongArray();
long carry = 0;
for (int i = raw.length - 1; i >= 0; i--) {
long newcarry = raw[i] << -n;
raw[i] = (raw[i] >>> n) | carry;
carry = newcarry;
}
return BitSet.valueOf(raw);
}