1. 程式人生 > >Java BitSet使用場景和示例

Java BitSet使用場景和示例

一、什麼是BitSet?

  注:以下內容來自JDK API:

  BitSet類實現了一個按需增長的位向量。位Set的每一個元件都有一個boolean值。用非負的整數將BitSet的位編入索引。可以對每個編入索引的位進行測試、設定或者清除。通過邏輯與、邏輯或和邏輯異或操作,可以使用一個 BitSet修改另一個 BitSet的內容。 

  預設情況下,set 中所有位的初始值都是false。 

  每個位 set 都有一個當前大小,也就是該位 set 當前所用空間的位數。注意,這個大小與位 set 的實現有關,所以它可能隨實現的不同而更改。位 set 的長度與位 set 的邏輯長度有關,並且是與實現無關而定義的。 

回到頂部

Java BitSet API簡介

()
          建立一個新的位 set。

(int nbits)
          建立一個位 set,它的初始大小足以顯式表示索引範圍在 0 到 nbits-1 的位。

void

and
          對此目標位 set 和引數位 set 執行邏輯操作。

void


          清除此 BitSet 中所有的位,其相應的位在指定的 BitSet 中已設定。

int

()
          返回此 BitSet 中設定為 true 的位數。

void

clear()
          將此 BitSet 中的所有位設定為 false

void

clear(int bitIndex)
          將索引指定處的位設定為 false

void

clear(int fromIndex, int toIndex)
          將指定的 fromIndex(包括)到指定的 toIndex(不包括)範圍內的位設定為 false

clone()
          複製此 BitSet,生成一個與之相等的新 BitSet

boolean


          將此物件與指定的物件進行比較。

void

flip(int bitIndex)
          將指定索引處的位設定為其當前值的補碼。

void

flip(int fromIndex, int toIndex)
          將指定的 fromIndex(包括)到指定的 toIndex(不包括)範圍內的每個位設定為其當前值的補碼。

boolean

get(int bitIndex)
          返回指定索引處的位值。

get(int fromIndex, int toIndex)
          返回一個新的 BitSet,它由此 BitSet 中從 fromIndex(包括)到 toIndex(不包括)範圍內的位組成。

int

()
          返回此位 set 的雜湊碼值。

boolean


          如果指定的 BitSet 中有設定為 true 的位,並且在此 BitSet 中也將其設定為true,則返回 ture。

boolean

()
          如果此 BitSet 中沒有包含任何設定為 true 的位,則返回 ture。

int

()
          返回此 BitSet 的“邏輯大小”:BitSet 中最高設定位的索引加 1。

int

(int fromIndex)
          返回第一個設定為 false 的位的索引,這發生在指定的起始索引或之後的索引上。

int

(int fromIndex)
          返回第一個設定為 true 的位的索引,這發生在指定的起始索引或之後的索引上。

void

or
          對此位 set 和位 set 引數執行邏輯操作。

void

set(int bitIndex)
          將指定索引處的位設定為 true

void

set(int bitIndex, boolean value)
          將指定索引處的位設定為指定的值。

void

set(int fromIndex, int toIndex)
          將指定的 fromIndex(包括)到指定的 toIndex(不包括)範圍內的位設定為 true

void

set(int fromIndex, int toIndex, boolean value)
          將指定的 fromIndex(包括)到指定的 toIndex(不包括)範圍內的位設定為指定的值。

int

size()
          返回此 BitSet 表示位值時實際使用空間的位數。

void

xor
          對此位 set 和位 set 引數執行邏輯異或操作。

二、Java BitSet實現原理

  在java中,BitSet的實現位於java.util包中:

複製程式碼

public class BitSet implements Cloneable, java.io.Serializable 
{
    private final static int ADDRESS_BITS_PER_WORD = 6;
    private final static int BITS_PER_WORD = 1 << ADDRESS_BITS_PER_WORD;
    private final static int BIT_INDEX_MASK = BITS_PER_WORD - 1;

    /* Used to shift left or right for a partial word mask */
    private static final long WORD_MASK = 0xffffffffffffffffL;

    private static final ObjectStreamField[] serialPersistentFields =
     {
        new ObjectStreamField("bits", long[].class),
    };

    /**
     * The internal field corresponding to the serialField "bits".
     */
    private long[] words;
    
    .....
}

複製程式碼

  可以看到,BitSet的底層實現是使用long陣列作為內部儲存結構的,所以BitSet的大小為long型別大小(64位)的整數倍。

  它有兩個建構函式:

  1、BitSet():建立一個新的位 set,預設大小是64位。

 public BitSet() 
{
        initWords(BITS_PER_WORD);
        sizeIsSticky = false;
}

  2、BitSet(int nbits):建立一個位set,它的初始大小足以顯式表示索引範圍在 0 到 nbits-1 的位。

複製程式碼

    public BitSet(int nbits)
     {
        // nbits can't be negative; size 0 is OK
        if (nbits < 0)
            throw new NegativeArraySizeException("nbits < 0: " + nbits);
        initWords(nbits);
        sizeIsSticky = true;
    }

複製程式碼

  注:

  1、如果指定了bitset的初始化大小,那麼會把他規整到一個大於或者等於這個數字的64的整倍數。比如64位,bitset的大小是1個long,而65位時,bitset大小是2個long,即128位。做這麼一個規定,主要是為了記憶體對齊,同時避免考慮到不要處理特殊情況,簡化程式。

  2:BitSet的size方法:返回此 BitSet 表示位值時實際使用空間的位數,值是64的整數倍

   length方法:返回此 BitSet 的“邏輯大小”:BitSet 中最高設定位的索引加 1  

回到頂部

三、使用場景

   常見的應用場景是對海量資料進行一些統計工作,比如日誌分析、使用者數統計等。

  之前在阿里的實習面試就被問到一道題:有1千萬個隨機數,隨機數的範圍在1到1億之間。現在要求寫出一種演算法,將1到1億之間沒有在隨機數中的數求出來?

  程式碼示例如下: 

複製程式碼

public class Alibaba
{
    public static void main(String[] args)
    {
        Random random=new Random();
        
        List<Integer> list=new ArrayList<>();
        for(int i=0;i<10000000;i++)
        {
            int randomResult=random.nextInt(100000000);
            list.add(randomResult);
        }
        System.out.println("產生的隨機數有");
        for(int i=0;i<list.size();i++)
        {
            System.out.println(list.get(i));
        }
        BitSet bitSet=new BitSet(100000000);
        for(int i=0;i<10000000;i++)
        {
            bitSet.set(list.get(i));
        }
        
        System.out.println("0~1億不在上述隨機數中有"+bitSet.size());
        for (int i = 0; i < 100000000; i++)
        {
            if(!bitSet.get(i))
            {
                System.out.println(i);
            }
        }     
    }
}

複製程式碼