BitMap的原理以及運用

  

位圖(Bitmap),即位(Bit)的集合,是一種數據結構,可用於記錄大量的0-1狀態,在不少地方都會用到,好比Linux內核(如inode,磁盤塊)、Bloom Filter算法等,其優點是能夠在一個很是高的空間利用率下保存大量0-1狀態。html

 

BitMap的原理java

  BitMap 的基本原理就是用一個bit 位來存放某種狀態,適用於大規模數據,但數據狀態又不是不少的狀況。一般是用來判斷某個數據存不存在的。node

  舉例:Java裏面一個int類型佔4個字節,假如要對於10億int數據進行處理呢?10億*4/1024/1024/1024=4個G左右,須要4個G的內存。  算法

            若是可以採用bit儲,10_0000_0000Bit=1_2500_0000byte=122070KB=119MB, 那麼在存儲空間方面能夠大大節省。數組

  在Java裏面,BitMap已經有對應實現的數據結構類java.util.BitSet,BitSet的底層使用的是long類型的數組來存儲元素。數據結構

  咱們來看看具體存儲:函數

  對於1,3,5,7這四個數,若是存在的話,則能夠這樣表示:測試

  

  1表明這個數存在,0表明不存在。例如表中01010101表明1,3,5,7存在,0,2,4,6不存在。那若是8,10,14也存在怎麼存呢?如圖,8,10,14咱們能夠存在第二個字節裏大數據

    

   以此類推。spa

Map映射表

    假設須要排序或者查找的總數N=10000000,那麼咱們須要申請內存空間的大小爲int a[1 + N/32],其中:a[0]在內存中佔32爲能夠對應十進制數0-31,依次類推: 
    bitmap表爲: 
   a[0]--------->0-31 
   a[1]--------->32-63 
   a[2]--------->64-95 
   a[3]--------->96-127 
   .......... 

BitMap算法處理大數據問題的場景

 (1)給定10億個不重複的正int的整數,沒排過序的,而後再給一個數,如何快速判斷這個數是否在那10億個數當中。

解法:遍歷40個億數字,映射到BitMap中,而後對於給出的數,直接判斷指定的位上存在不存在便可。

 (2)使用位圖法判斷正整形數組是否存在重複

解法:遍歷一遍,存在以後設置成1,每次放以前先判斷是否存在,若是存在,就表明該元素重複。

 (3)使用位圖法進行元素不重複的正整形數組排序

解法:遍歷一遍,設置狀態1,而後再次遍歷,對狀態等於1的進行輸出,參考計數排序的原理。

 (4)在2.5億個整數中找出不重複的正整數,注,內存不足以容納這2.5億個整數

解法1:採用2-Bitmap(每一個數分配2bit,00表示不存在,01表示出現一次,10表示屢次,11無心義)。

解法2:採用兩個BitMap,即第一個Bitmap存儲的是整數是否出現,接着,在以後的遍歷先判斷第一個BitMap裏面是否出現過,若是出現就設置第二個BitMap對應的位置也爲1,最後遍歷BitMap,僅僅在一個BitMap中出現過的元素,就是不重複的整數。

解法3:分治+Hash取模,拆分紅多個小文件,而後一個個文件讀取,直到內存裝的下,而後採用Hash+Count的方式判斷便可。

該類問題的變形問題,如已知某個文件內包含一些電話號碼,每一個號碼爲8位數字,統計不一樣號碼的個數。8位最多99 999 999,大概須要99m個bit,大概10幾m字節的內存便可。 (能夠理解爲從0-99 999 999的數字,每一個數字對應一個Bit位,因此只須要99M個Bit==12MBytes,這樣,就用了小小的12M左右的內存表示了全部的8位數的電話)

BitMap的一些缺點:

1)數據碰撞。好比將字符串映射到 BitMap 的時候會有碰撞的問題,那就能夠考慮用 Bloom Filter 來解決,Bloom Filter 使用多個 Hash 函數來減小衝突的機率。

2)數據稀疏。又好比要存入(10,8887983,93452134)這三個數據,咱們須要創建一個 99999999 長度的 BitMap ,可是實際上只存了3個數據,這時候就有很大的空間浪費,碰到這種問題的話,能夠經過引入 Roaring BitMap 來解決。

例子:

   從正整數數組中尋找重複的整數

  

import java.util.BitSet;
import java.util.HashSet;
import java.util.Set;

public class TestBitMap {
        //假設數據是以數組的形式給咱們的
        public static Set test(int[] arr) {
            int j = 0;
            //避免返回重複的數,存在Set裏
            Set output = new HashSet();
            BitSet bitSet = new BitSet(Integer.MAX_VALUE);
            int i = 0;
            while (i < arr.length) {
                int value = arr[i];
                //判斷該數是否存在bitSet裏
                if (bitSet.get(value)) {
                    output.add(value);
                } else {
                    bitSet.set(value, true);
                }
                i++;
            }
            return output;
        }
        //測試
        public static void main(String[] args) {
            int[] t = {1,2,3,4,5,6,7,8,3,4,9};
            Set t2 = test(t);
            System.out.println(t2);
        }
    }

 

總結

     本文主要介紹了BitMap算法的基本原理和應用案例,其本質上是採用了bit位來表示元素狀態,從而在特定場景下可以極大的節省存儲空間,很是適合對海量數據的查找,判重,刪除等問題的處理。

其餘參考:

http://www.javashuo.com/article/p-xachuatg-cs.html

https://www.cnblogs.com/gczr/p/7358813.html

相關文章
相關標籤/搜索