1. 程式人生 > >BitSet 是個好東西

BitSet 是個好東西

add ear style index sys 設置 blog left 64bit

顧名思義,就是位集合(bit set),是從JDK 1.0就出現的東西,後面的版本又慢慢強化。

我們說學習一樣東西,最好是場景驅動 - 要考慮它的使用場景,這樣才有意義。

那麽,BitSet的應用場景是什麽?

我個人的體會是,用於統計,統計整數相關的東西。但這麽說未免太空泛了,我們先來看一下它的用法吧。

直接上例子:

@Test
public void test(){
    BitSet set = new BitSet(10); //10 bits set

    //set() 設為true
    set.set(0);
    set.set(1);
    set.set(5);
    System.out.println(set); 
// 應該是列出值為true的那些位的坐標! // 8 bit >> 1 byte, 就是說截取8位,轉成byte。 就是0010 0011 >> System.out.println(Arrays.toString(set.toByteArray())); // 64 bit >> 1 long System.out.println(Arrays.toString(set.toLongArray())); }
 

方法體內:

第一部分是創建對象,該構造方法接收一個int來指明位集合的長度 -- [0,0,0,0, 0,0,0,0, 0,0]。註意,此時所有位的值都是false - 這裏的false不是Java中的概念,而是對應bit的0 -- true對應1。

第二部分是設置位值,BitSet#set(int n) 方法是將第n位的值設為true(1) -- [1,1,0,0, 0,1,0,0, 0,0]!直接輸出的話,就是位值為true的索引:{0, 1, 5}!

第三部分,是將所有位轉成byte數組、long數組,並輸出對應的數組內容。轉成byte[],其實就是每8位切分一下;轉成long[]就是每64位切分一下!那麽[1,1,0,0, 0,1,0,0, 0,0]就是[(1,1,0,0, 0,1,0,0,) 0,0],也就是[35]!註意計算方式。

再來一個逆向的例子:

@Test
public void test1(){
    // 和test()中的set.toByteArray()剛好相反,這裏是1 byte >> 8 bits! 需要確認90對應的低8bit 還是高8bit。
BitSet bitSet = BitSet.valueOf(new byte[]{90, 92, 95, 97}); System.out.println(bitSet); //{1, 3, 4, 6, 10, 11, 12, 14, 16, 17, 18, 19, 20, 22, 24, 29, 30} //截取下上面的輸出即可知道90對應的是低位還是高位 BitSet bs = new BitSet(8);// bs.set(1); bs.set(3); bs.set(4); bs.set(6); System.out.println(Arrays.toString(bs.toByteArray()));//90 - 事實證明是小端? }

這裏就是將byte[]或long[]中的每個值拆成8bit或者64bit的形式,填入相應的位置(8*index ~ 8*(index+1),或64*index ~ 64*(index+1))。

然後,具體的計算就跟2進制轉8進制或16進制一樣,每三位一算,或每四位一算!只不過這裏是每8位或每64位一算!

那回到前面的主題,這有什麽應用場景?

舉個例子,比如你要生成隨機數,整數,不多,就 0~1億範圍吧,生成的數量不定,現在讓你列出所有生成的數值,甚至按照大小排序,你怎麽做?

難道是搞一個HashSet<Integer>?哪怕是按照int類型的長度,最大也會4B*100000000 ≈ 381 MB,性能絕對是個問題,還得排序,估計得到地老天荒。

用BitSet就方便多了,怎麽用呢?

直接搞一個 new BitSet(100000000),內存不過是 100000000/8 B ≈ 12 MB!

然後,每得到一個隨機數,就將相應的位設為true即可,bs.set(num)!

最後,直接輸出所有位值為true的索引即可,無論從小到大,還是反過來,都很簡單!

怎麽樣,有沒有一種驚喜的感覺,哈哈,起碼我覺得很驚喜。

噢對了,這貨C++中也有。

至於BitSet其他的操作,留給各位自行探索吧。

BitSet 是個好東西