布隆过滤器(Java实现)

本文介绍了一种高效的数据结构——布隆过滤器,它能够快速判断元素是否存在于集合中,尤其适用于大数据环境下。文章详细阐述了布隆过滤器的工作原理、优缺点及其Java实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

布隆过滤器

布隆过滤器是可以用于判断一个元素是不是在一个集合里,并且相比于其它的数据结构,布隆过滤器在空间和时间方面都有巨大的优势。
优点:占用空间小,查询快
缺点:有误判,删除困难

具体原理:链接

简单易懂的描述:
布隆过滤器。其实现方法就是:利用内存中一个长度为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%正确率的条件限制,换取了空间复杂度的进一步缩小。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值