移动Java位集

移动Java位集,java,bitset,bit-shift,Java,Bitset,Bit Shift,我使用java.util.BitSet来存储密集的位向量 我想实现一个将位右移1的操作,类似于int上的> 是否有一个库函数可以移位位集s 如果没有,还有比下面更好的方法吗 public static void logicalRightShift(BitSet bs) { for (int i = 0; (i = bs.nextSetBit(i)) >= 0;) { // i is the first bit in a run of set bits. // Set

我使用
java.util.BitSet
来存储密集的位向量

我想实现一个将位右移1的操作,类似于int上的
>

是否有一个库函数可以移位
位集
s

如果没有,还有比下面更好的方法吗

public static void logicalRightShift(BitSet bs) {
  for (int i = 0; (i = bs.nextSetBit(i)) >= 0;) {
    // i is the first bit in a run of set bits.

    // Set any bit to the left of the run.
    if (i != 0) { bs.set(i - 1); }

    // Now i is the index of the bit after the end of the run.
    i = bs.nextClearBit(i);  // nextClearBit never returns -1.
    // Clear the last bit of the run.
    bs.clear(i - 1);

    // 0000111100000...
    //     a   b
    // i starts off the loop at a, and ends the loop at b.
    // The mutations change the run to
    // 0001111000000...
  }
}

另一种可能更有效的方法是使用基础的long[]

使用
bitset.toLongArray()
获取底层数据。相应地移动这些长度,然后通过
BitSet.valueOf(long[])
创建一个新的位集。您必须非常小心地移动基础的长度,因为您必须在数组中的下一个长度上将低阶位移到高阶位

这应该允许您使用处理器上的本机位移位操作一次移动64位,而不是单独迭代每个位


编辑:根据路易斯·瓦瑟曼的评论。这仅在Java1.7API中可用。当我写它的时候,我没有意识到这一点。

这应该可以做到:

BitSet shifted = bs.get(1, bs.length());
它将为您提供一个与原始位相同的位集,但没有最低位

编辑:

要将其推广到
n

BitSet shifted = bs.get(n, Math.max(n, bs.length()));

您可以查看位集
toLongArray
值(long[])


基本上获取
long
数组,移动
long
s,并从移动的数组中构造一个新的
位集。

请找到位集“左移”的这个代码块

/**
*将位集向左移动。
*例如:0b10010(=18)=>0b100100(=36)(相当于乘以2) *@param位集 *@返回移位位集 */ 公共静态位集leftShiftBitSet(位集位集){ 最终长面罩=0x80000000000000L; long[]沿=bitSet.toLongArray(); 布尔进位=假; 对于(int i=0;i<沿长度;++i){ 如果(携带){ 进位=((沿[i]和maskOfCarry)!=0); 沿[i]方向,这些函数分别模拟>>运算符

/**
 * Shifts a BitSet n digits to the left. For example, 0b0110101 with n=2 becomes 0b10101.
 *
 * @param bits
 * @param n the shift distance.
 * @return
 */
public static BitSet shiftLeft(BitSet bits, int n) {
    if (n < 0)
        throw new IllegalArgumentException("'n' must be >= 0");
    if (n >= 64)
        throw new IllegalArgumentException("'n' must be < 64");

    long[] words = bits.toLongArray();

    // Do the shift
    for (int i = 0; i < words.length - 1; i++) {
        words[i] >>>= n; // Shift current word
        words[i] |= words[i + 1] << (64 - n); // Do the carry
    }
    words[words.length - 1] >>>= n; // shift [words.length-1] separately, since no carry

    return BitSet.valueOf(words);
}

/**
 * Shifts a BitSet n digits to the right. For example, 0b0110101 with n=2 becomes 0b000110101.
 *
 * @param bits
 * @param n the shift distance.
 * @return
 */
public static BitSet shiftRight(BitSet bits, int n) {
    if (n < 0)
        throw new IllegalArgumentException("'n' must be >= 0");
    if (n >= 64)
        throw new IllegalArgumentException("'n' must be < 64");

    long[] words = bits.toLongArray();

    // Expand array if there will be carry bits
    if (words[words.length - 1] >>> (64 - n) > 0) {
        long[] tmp = new long[words.length + 1];
        System.arraycopy(words, 0, tmp, 0, words.length);
        words = tmp;
    }

    // Do the shift
    for (int i = words.length - 1; i > 0; i--) {
        words[i] <<= n; // Shift current word
        words[i] |= words[i - 1] >>> (64 - n); // Do the carry
    }
    words[0] <<= n; // shift [0] separately, since no carry

    return BitSet.valueOf(words);
}
/**
*将位集n位向左移动。例如,n=2的0b0110101变为0b10101。
*
*@param位
*@param n移动距离。
*@返回
*/
公共静态位集移位(位集位,int n){
if(n<0)
抛出新的IllegalArgumentException('n'必须大于等于0”);
如果(n>=64)
抛出新的IllegalArgumentException('n'必须小于64”);
long[]字=位。toLongArray();
//轮班
for(int i=0;i>>>=n;//移位当前字
单词[i]|=单词[i+1]>>=n;//分别移位[words.length-1],因为没有进位
返回BitSet.valueOf(字);
}
/**
*将位集n位向右移动。例如,n=2的0b0110101变为0b000110101。
*
*@param位
*@param n移动距离。
*@返回
*/
公共静态位集移位触发器(位集位,int n){
if(n<0)
抛出新的IllegalArgumentException('n'必须大于等于0”);
如果(n>=64)
抛出新的IllegalArgumentException('n'必须小于64”);
long[]字=位。toLongArray();
//如果有进位,则展开数组
如果(字[words.length-1]>>>(64-n)>0){
long[]tmp=新长[words.length+1];
System.arraycopy(字,0,tmp,0,字.长度);
单词=tmp;
}
//轮班
对于(int i=words.length-1;i>0;i--){
单词[i]>(64-n);//进行进位
}

words[0]为了获得更好的性能,您可以扩展java.util.BitSet实现并避免不必要的数组复制。以下是实现(我基本上重用了Jeff Piersol实现):

package first.specific.structure;
导入java.lang.reflect.Field;
导入java.util.BitSet;
公共类BitSetMut扩展了BitSet{
私人长[]字;
私有静态字段wordsField;
静止的{
试一试{
wordsField=BitSet.class.getDeclaredField(“words”);
wordsField.setAccessible(true);
}捕获(无此字段例外){
抛出新的非法状态异常(e);
}
}
公共位setmut(最终整数regLength){
超级(regLength);
试一试{
words=(long[])wordsField.get(this);
}捕获(非法访问例外e){
抛出新的非法状态异常(e);
}
}
公共无效移位(整数n){
if(n<0)
抛出新的IllegalArgumentException('n'必须大于等于0”);
如果(n>=64)
抛出新的IllegalArgumentException('n'必须小于64”);
如果(words.length>0){
保证能力(n);
//轮班
对于(int i=words.length-1;i>0;i--){
单词[i]>(64-n);//进行进位
}
字[0]>n>0){
long[]tmp=新长[words.length+3];
System.arraycopy(字,0,tmp,0,字.长度);
单词=tmp;
试一试{
wordsField.set(这个,tmp);
}捕获(非法访问例外e){
抛出新的非法状态异常(e);
}
}
}
}

您可以使用
biginger
而不是
BitSet
biginger
已经有ShiftRight和ShiftLeft。

使用java SE8,可以通过更简洁的方式实现:

BitSet b = new BitSet();
b.set(1, 3);
BitSet shifted = BitSet.valueOf(Arrays.stream(
       b.toLongArray()).map(v -> v << 1).toArray());
位集b=新位集();
b、 组(1,3);
位集移位=位集.valueOf(Arrays.stream(

b、
get
上的[documentation](,int))映射(v->v)使我感到困惑。“返回一个新的位集,该位集由从索引(包含)到索引(独占)的位组成。”表示此
fromIndex
处的位映射到输出中的
0
。@Mike。它的工作原理类似于
String.substring(begin,end)
。请注意,此ca中的
begin
package first.specific.structure;

import java.lang.reflect.Field;
import java.util.BitSet;

public class BitSetMut extends BitSet {

    private long[] words;
    private static Field wordsField;

    static {
        try {
            wordsField = BitSet.class.getDeclaredField("words");
            wordsField.setAccessible(true);
        } catch (NoSuchFieldException e) {
            throw new IllegalStateException(e);
        }
    }

    public BitSetMut(final int regLength) {
        super(regLength);
        try {
            words = (long[]) wordsField.get(this);
        } catch (IllegalAccessException e) {
            throw new IllegalStateException(e);
        }
    }

    public void shiftRight(int n) {
        if (n < 0)
            throw new IllegalArgumentException("'n' must be >= 0");
        if (n >= 64)
            throw new IllegalArgumentException("'n' must be < 64");

        if (words.length > 0) {
            ensureCapacity(n);

            // Do the shift
            for (int i = words.length - 1; i > 0; i--) {
                words[i] <<= n; // Shift current word
                words[i] |= words[i - 1] >>> (64 - n); // Do the carry
            }
            words[0] <<= n; // shift [0] separately, since no carry
            // recalculateWordInUse() is unnecessary
        }
    }

    private void ensureCapacity(final int n) {
        if (words[words.length - 1] >>> n > 0) {
            long[] tmp = new long[words.length + 3];
            System.arraycopy(words, 0, tmp, 0, words.length);
            words = tmp;
            try {
                wordsField.set(this, tmp);
            } catch (IllegalAccessException e) {
                throw new IllegalStateException(e);
            }
        }
    }
}
BitSet b = new BitSet();
b.set(1, 3);
BitSet shifted = BitSet.valueOf(Arrays.stream(
       b.toLongArray()).map(v -> v << 1).toArray());