布隆過濾器(Java實現)

布隆過濾器

布隆過濾器是可以用於判斷一個元素是不是在一個集合裏,並且相比於其它的數據結構,布隆過濾器在空間和時間方面都有巨大的優勢。
優點:佔用空間小,查詢快
缺點:有誤判,刪除困難

具體原理:鏈接

簡單易懂的描述:
布隆過濾器。其實現方法就是:利用內存中一個長度爲M的位數組B並初始化裏面的所有位都爲0,如下面的表格所示:

0 0 0 0 0 0 0 0 0 0

然後我們根據H個不同的散列函數,對傳進來的字符串進行散列,並且每次的散列結果都不能大於位數組的長度。布隆過濾器的誤判率取決於你使用多少個不同的散列函數。現在我們先假定有4個不同散列函數,傳入一個字符串並進行一次插入操作,這時會進行4次散列,假設到了4個不同的下標,這個時候我們就會去數組中,將這些下標的位置置爲1,數組變更爲:
0 1 0 1 1 0 0 0 0 1

如果接下來我們再傳入同一個字符串時,因爲4次的散列結果都是跟上一次一樣的,所以會得出跟上面一樣的結果,所有應該置1的位都已經置1了,這個時候我們就可以認爲這個字符串是已經存在的了。因此不難發現,這是會存在一定的誤判率的,具體由你採用的散列函數質量,以及散列函數的數量確定。

最最原始的Java實現:
只做過簡單測試(嗯。。。應該沒問題吧)

import java.util.BitSet;


/**
 * 最最原始的布隆過濾器類
 */
public class SimpleBloomFilter
{
    // 設置布隆過濾器的大小
    private static final int DEFAULT_SIZE = 2 << 24;
    // 產生隨機數的種子,可產生6個不同的隨機數產生器。。。而且最好取素數
    private static final int[] seeds = new int[]{7, 11, 13, 31, 37, 61};
    // Java中的按位存儲的思想,其算法的具體實現(布隆過濾器)
    private BitSet bits = new BitSet(DEFAULT_SIZE);
    // 根據隨機數的種子,創建6個哈希函數
    private SimpleHash[] func = new SimpleHash[seeds.length];

    // 設置布隆過濾器所對應k(6)個哈希函數
    public SimpleBloomFilter()
    {
        for (int i = 0; i < seeds.length; i++)
        {
            func[i] = new SimpleHash(DEFAULT_SIZE, seeds[i]);
        }
    }

    public static void main(String[] args)
    {
        SimpleBloomFilter filter = new SimpleBloomFilter();
        filter.add("123");
        System.out.println(filter.contains("123"));
        System.out.println(filter.contains("124"));
        filter.add("124");
        System.out.println(filter.contains("124"));
    }


    /**
     * 添加
     * @param str 值
     */
    public void add(String str)
    {
        // 集齊6個hash值,準備(召喚神龍)添加
        for (SimpleHash f:func)
        {
            bits.set(f.hash(str));
        }
    }


    /**
     * 判斷是否存在
     * @param str
     * @return
     */
    public boolean contains(String str)
    {
        // 根據此URL得到在布隆過濾器中的對應位,並判斷其標誌位(6個不同的哈希函數產生6種不同的映射)
        for (SimpleHash f : func)
        {
            //當存在六位不都爲0時,返回false
            if (!bits.get(f.hash(str)))
            {
                return false;
            }
        }
        return true;
    }


    /**
     * 哈希類
     */
    public static class SimpleHash
    {
        private int cap;
        private int seed;

        // 默認構造器,哈希表長默認爲DEFAULT_SIZE大小,此哈希函數的種子爲seed
        public SimpleHash(int cap, int seed)
        {
            this.cap = cap;
            this.seed = seed;
        }

        public int hash(String value)
        {
            int result = 0;
            int len = value.length();

            for (int i = 0; i < len; i++)
            {
                // 散列函數...重點,將此URL(使用到了集合中的每一個元素)散列到一個值
                result = seed * result + value.charAt(i);
            }

            // 產生單個信息指紋。。。不能直接返回result,可能會越界
            return (cap - 1) & result;
        }
    }
}


思考:

1.雖然布隆過濾器的數學原理好像很複雜的樣子,但是真正實現起來並不是特別困難。。。。只是數學證明與描述。。。。。真的有點難

2.有所得,必有所失
就像基於比較的排序算法的時間複雜度下限是O(nLgn)一樣,滿足100%正確率,時間複雜度爲O(1)的去重算法的空間複雜度下限應該是很接近於簡單的hash算法了(沒找到論文,不負責任的猜測一下)
而想要進一步降低空間複雜度,可能就需要放寬去重條件的限制了,比如去掉時間複雜度爲O(1),那麼做到空間複雜度爲O(1)都是很簡單的事。
而布隆過濾器就相當於去掉了100%正確率的條件限制,換取了空間複雜度的進一步縮小。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章