今天看到了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,極大地節省了存儲空間。