BitSet
前言
最近用到了位圖索引的相關知識,第一次接觸Java中進行位向量運算的工具類BitSet,簡單學習記錄一下。
一、簡介
功能
BitSet類是一種用來保存位值的特殊數組,數組的大小可以改變。它和位向量的功能類似。
實現原理
源碼中的介紹如下:
BitSets are packed into arrays of "words." Currently a word is a long, which consists of 64 bits, requiring 6 address bits.The choice of word size is determined purely by performance concerns.
簡言之:
BitSet的數據封裝到一個叫words的數組中,數組中的每一個word都是一個long類型的數據(我的理解是:位向量需要表示為人最容易理解的形式-整數,而表示整數的數據類型中,long的長度最長,為8字節64bit,64bit可以表示64種事物的狀態)
words = new long[wordIndex(nbits-1) + 1];
二、方法
BitSet類的兩種構造方法
-
無參構造
BitSet bs3 = new BitSet();
默認長度為1;
-
有參構造
BitSet bs1 = new BitSet(4);
常用方法
-
length() 返回BitSet的邏輯長度
BitSet bs1 = new BitSet(4); System.out.println(bs3.length()); bs3.set(2); System.out.println(bs3.length());
輸出為:0和3
輸出為0是因為:bs1的各個位均為false,即0000,所以邏輯長度為0
輸出為3是因為:bs1變為0010,所以邏輯長度為3
-
get(i) 獲得i位置的位符號(true or false)
for (int i = 0; i <4 ; i++) { if (i%2 == 0) bs1.set(i);//把i位置設為true } for (int i = 0; i <4 ; i++) { if(bs1.get(i)){ System.out.print("1"); } if(!bs1.get(i)) { System.out.print("0"); } }
輸出為:1010
注:i可以取大於0的任何整數值,但不能取小於0的值;即get(-1)會報錯。
-
println(s1): 輸出bs1中為true的位所在的索引
輸出為:{0, 2}
-
and(bs2)
bs1.and(bs2); 輸出為: ====qian== bs1:1010 bs2:0110 ====hou== bs1:0010 bs2:0110
-
andNot(bs1):bs1中0和2所在的位為1,則將bs2中0和1所在的位設置為0;
bs2.andNot(bs1); 輸出為: ====qian== bs1:1010 bs2:0110 ====and== bs1:1010 bs2:0100
-
or:或操作
-
xor:異或操作;不同取1,相同取0
-
int cardinality( ):返回BitSet 中設置為 true 的位數。
System.out.println(bs1.cardinality());輸出為2;
-
clear(int index);clear();clear(int startIndex, int endIndex):將true變成false
-
BitSet get(int startIndex, int endIndex):返回一個新的BitSet ,長度為endIndex-startIndex
bs2:0110BitSet bitSet = bs2.get(1, 3);輸出:11
-
boolean intersects(BitSet bitSet):判斷兩個BitSet 中true所在的位置是否相等;二者的長度不限制
-
int nextSetBit(int startIndex):從startIndex開始,第一個出現true的位置
bs1:1010System.out.println(bs1.nextSetBit(1));System.out.println(bs1.nextSetBit(0));輸出為:20
-
int size( ):Returns the number of bits of space actually in use by this {@code BitSet} to represent bit values.
BitSet bs2 = new BitSet(63);BitSet bs3 = new BitSet(65);System.out.println(bs2.size());System.out.println(bs3.size());輸出為:64128
即:BitSet的空間實際使用的單位為64bit
三、補充說明
-
情況1
BitSet bs1 = new BitSet(6);BitSet bs2 = new BitSet(63);System.out.println(bs1.length());for (int i = 0; i <63 ; i++) { if (i%2 == 0) bs1.set(i);//把i位置設為true}for (int i = 0; i <2 ; i++) { bs2.set(i);//把i位置設為true}bs2.xor(bs1);System.out.println(bs1.size());System.out.println(bs2.size());
輸出為:64 和 64(因為bs1和bs2賦值的時候,長度都沒有超過64)
-
情況2
BitSet bs1 = new BitSet(6);BitSet bs2 = new BitSet(63);System.out.println(bs1.length());for (int i = 0; i <65 ; i++) { if (i%2 == 0) bs1.set(i);//把i位置設為true}for (int i = 0; i <2 ; i++) { bs2.set(i);//把i位置設為true}bs2.xor(bs1);System.out.println(bs1.size());System.out.println(bs2.size());
輸出為:128 和 128(因為bs1賦值的時候長度超過64,並且和bs1進行了位運算,所以長度都變成了128)
如果把bs2.xor(bs1);去掉,輸出結果為128和64
四、總結
- BitSet底層是用long類型的數據進行存儲的,且長度單位為64,比如需要表示001,則實際001 = 00100...0(64位)
- 當長度超過64位時,比如需要表示0010000..0(68位),會用兩個long類型的數據表示該BitSet,即實際的001000..00(68位) = [001000..0(64位),000000000(64位)]
- 當兩個長度不同的BitSet進行運算時,比如001(3位)和0010000..0(68位)進行運算,最終它們的長度均為68位,實際占有空間的大小為128bit。