今天看到了java集合当中的一个位集BitSet,先说一下BitSet,BitSet类用于存放一个位序列,如果需要高效的存储位序列可以使用位集,因为位集将位包装在了字节里面,所以使用位集要比使用Boolean对象的ArrayList更为高效
BitSet取值为true和false,在API里面有以下几个方法:
BitSet(int initialCapacity) 创建一个位集
int length( ) 返回位集的“逻辑长度”,即1加上位集的最高设置位置的索引值
boolean get(int bit) 获得一个位
void set(int bit) 设置一个位
void clear(int bit) 清除一个位
void and(BitSet set) 这个位集和另一个位集进行逻辑“AND”
void or(BitSet set) 这个位集和另一个位集进行逻辑“OR”
void xor(BitSet set) 这个位集和另一个位集进行逻辑“XOR”(异或运算)
void andNot(BitSet set) 清除这个位集中对应另一个位集中设置的所有位
好的,接下来介绍一下Eratosthenes筛选法(埃拉托斯特尼筛选法),这个算法并不是一种查找素数的最好方法,但是由于某些原因,它已经成为了测试编译程序性能的一种流行的基准(这也不是一种最好的基准测试方法,它主要用于位操作)
Eratosthenes筛选法的主要逻辑就是不必运用除法而找到2~N之间的素数,比如开始是i,想办法把i的倍数都筛选出去,然后剩下的数就是质数
例子是求2~2000000之间的所有素数
代码:
import java.util.BitSet;
public class Eratosthenes {
public static void main(String[] args) {
int n = 2000000; //判断2000000以内的素数
BitSet b = new BitSet(n+1);
int count = 0;
int i;
for(i = 2; i <= n; i++) //把各个位都置为true
b.set(i);
i = 2;
while(i * i <= n){
if(b.get(i)){
System.out.println(i);
count++;
int k = 2 * i;
while(k <= n){ //筛选掉i的倍数的数,i的倍数一定能被i整除,i的倍数一定不是素数
b.clear(k); //将i的倍数位置为false
k += i;
}
}
i++;
}
while(i <= n){ //判断i以后的数的位是否为true
if(b.get(i))
count++;
i++;
}
System.out.println("一共有"+count+"个素数");
}
}
其实这个算法有很多可以优化的地方,比如除了2以外的偶数一定不是素数,所以可以只考虑奇数,写这篇文章的主要目的就是记录一下BitSet这个类的用法
BitSet是可以按位存储的,我们知道,在计算机中一个字节(byte)占8位(bit),而且在java里面数据至少得是按字节存储的,如果遇到大的数据量的话,就相当的占用内存了
比如说一个int占4个字节,就是4*8=32位(bit)
当我们存储一个整型2的话,用BitSet的话就可以用到一个位,因为BitSet是这样进行的,先声明一个BitSet,大小为2+1,然后将第2位设置为true,最后的结果是[false,false,true],所以它存的是整数2,只用了一个位就搞定了,占用的内存比例可是32:1,极大地节省了存储空间。