BitMap位图理解及典型应用案例

基本介绍

        本质上是哈希表的一种应用实现,原理简单,以 bit 为单位构建数组的方案,就叫作 Bitmap,翻译为位图。即bit 的集合;使用一个bit表示状态, 两种状态 (0不存在和1存在) 使用最少字节的类型来定义数组,即最小的空间存储数据标识。

        位图适合对【数值类型】的海量数据进行查询统计、排序、去重 和 对两个集合做交集、并集运算;bitmap在数据连续的时候,非常节省空间,但是在数据稀疏的时候,会有极大的浪费,当出现hash碰撞时可能映射到同个位置;

业务应用

        日活/月活UV统计、签到统计、用户点赞,用户签到,访问计数,在线用户数等

典型案例应用解析

1)找存在的UserId

        一个32位4G内存的操作系统,在20亿个整数,找出某个数X是否存在其中,在Java环境中int占4个字节,一个字节占8位。

方式1:将用户id存到集合,那么需要消耗20亿*4*8=640亿位=640/8/1024/1024/1024=7.48GB

方式2:不存储具体数值,仅存储是否存在,存在1不存在0,20亿位/8/1024/1024/1024=0.23GB

解决方案:

1)使用数组处理

        每个int类型可标识32个整数,存储20亿个元素需要20亿个比特位,20亿/8/1024/1024 约上200多MB,省32倍空间。需要申请的数组大小,总的数组长度为20亿/32 +1。

array[0]:可表示0~31,array[1]:可表示32~63,array[2]可表示64~95

        如何确定位置(给定任意整数M,那么M/32就得到下标,M%32就知道它在此下标的哪个位置)

如元素存储 80,确定所在数组的bit位置
1、数组index索引  80/32 = 2.5,即第3个数组的位置 arr[2]
2、比特位index索引 80%32 = 16,索引下标为16的比特位,把比特位设置为1,即arr[2][16]

2)使用redis使用bitmap数据结构处理

Redis中提供的BitMap命令:setbit,getbit,bitcount


检测用户是存在(checkUserIsExsits是Key):setbit checkUserIsExsits user-uid 101024511
  例子:setbit checkUserIsExsits  101024511

是否存在判断:getbit  checkUserIsExsits  user-uid
  例子:getbit checkUserIsExsits 101024511
  如果不存在状态是0,如果已存在就是1
  
统计当前有多少个用户
  bitcount checkUserIsExsits
 返回值为该key值中1的个数

2)找不存在的随机数

需求:有1千万个随机数,随机数的范围在1到1亿之间,将1到1亿之间没有在随机数中的数求出来

前提条件:使用java现有数据结构或自定义数据结构,要求高效和省空间

解决方案:遍历X亿个数字,映射到BitMap中,对于给出的数,直接判断指定的位上存在不存在即可

public static void testBitMap2(){
        //范围
        int range = 100;
        //个数
        int totalNum = 10;

        List<Integer> list=new ArrayList<>();

        //1.声明一个BitSet
        BitSet bitSet = new BitSet(range);
        //2.生成1千万个随机数
        for (int i = 0; i < totalNum; i++) {
            int random = (int) (Math.random() * range);
            bitSet.set(random);
            list.add(random);
        }
        System.out.println("产生的随机数:"+list);
        System.out.println("bitmap是1的个数(存在重复随机送):"+bitSet.cardinality());
        System.out.println("bitmap是size:"+bitSet.size());
        System.out.println("bitmap是length(bitmap里面占据的位数是1的位数+1):"+bitSet.length());
        //3.遍历BitSet,将没有出现的数打印出来
        for (int i = 0; i < range; i++) {
            if (!bitSet.get(i)) {
                System.out.print(i+",");
            }
        }
    }

该数据结构缺点

数据碰撞:字符串映射到 bitmap会有碰撞问题,即可能映射到同个位置,即hash碰撞

稀疏数据:不连续的数据容易浪费空间,比如存入1和88两个数,需要构建长度89的数组,表示索引从1到88,所以需要构建一个长度为89的数组,存放1到88的元素,但实际只存储2个数字。

如果用户的ID的数据类型是int32的话,那么最大值是2^32,需要用512MB的字节的位图来表示,2^32bit=4294967296 比特(bit)=512 兆字节(MB)。

如果只往bitmap存储一个最大值,那边需要申请512 兆字节(MB),大大浪费空间

  • 26
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值