BitMap(位图)

BitMap定义

位图(BitMap),即位(Bit)的集合,是一个离散的数组结构,用一个bit位来标记某个元素对应的Value,而Key即是该元素;最基本的情况,使用一个bit表示一个关键字的状态(可标示两种状态0-不存在,1-存在),也可以使用2bit(表示4种状态),3bit(表示8种状态)需要根据业务场景实现。

BitMap 数据结构

数据结构:byte[],一个byte 8 bit,使用bit为单位来存储数据,可以在空间和时间双重维度提高效率。

注:也可以是 int[],long[],数据结构,分别表示32bit,64bit

一个int 4个字节 32 bit,使用 BitMap(byte[]) 一个bit 表示一个int 空间缩小32倍。

如:在Java里面一个int类型占4个字节,要对于20亿个int数据进行处理,20亿*4/1024/1024/1024≈7.5G左右,需要将尽8G的内存;BitMap(byte[])处理需要20亿/8/1024/1024/1024≈0.232G,内存不到0.5G,查询某个数据时间复杂度是o(n),校验数据时间复杂度o(1)

数组:[7,9,11,1,3,5],存储如下图

注:byte[] 下标  n/8 == n >>> 3 即向右位移3位;byte[]值域 1<< n%8 = ( n & 0x07) 即取模向左位移

BitMap 应用场景

1.多个超大文件取交集(数字文件)

2.从海量电话号码中,统计不同号码的个数

3.统计日活,访问量,如 redis.setbit('YYYY-MM-DD',Id,1);

4.BitMap处理大量数字型数据的排序、查询、去重

5.BitMap扩展——Bloom Filter(布隆过滤器)过滤数据(id)

BitMap 优缺点

优点:

1.运算效率高,不需要进行比较和移位;

2.占用内存少,比如: 20亿/8/1024/1024/1024≈0.232G

3.高效排序,去重,校验o(1),查询o(n)

4.可删除(存储数值型数据)

缺点:

1.所有的数据不能重复。即不可对重复的数据进行排序和查找。

2.只有当数据比较密集时才有优势

3.数据碰撞。比如将字符串hash映射到 BitMap 的时候会有碰撞的问题,那就可以考虑用 Bloom Filter 来解决,Bloom Filter 使用多个 Hash 函数来减少冲突的概率。

4.数据稀疏。比如要存入(9,55555555,99999999)这三个数据,需要建立一个 99999999/8+1 长度的 BitMap ,但是实际上只存了3个数据,这时候就会很大的空间浪费(少量数据不建议使用);可以通过引入 Roaring BitMap 来解决。

BitMap 手动实现源码逻辑

本次底层是数据结构使用byte[],实现,也可以使用 int[],long[]数据结果,注意初始化数组大小,防止内存不够

/**

* java运算符 与(&)、非(~)、或(|)、异或(^)

* BitMap 数据存储约 160 亿

* 存储方式为离散数组方式,建议大量连续数据使用

* @author ysf

*

*/

public class BitMap {

      private static final int MAXSIZE = Integer.MAX_VALUE-Short.MAX_VALUE;

      private byte[] bits;

      private long count=0;

      public BitMap() {

            bits = new byte[Integer.MAX_VALUE/2];

      }

      public BitMap(long maxNum) {

            long maxSize = (maxNum>>>3)+1;

            if(maxSize > Long.valueOf(MAXSIZE)){

                  bits = new byte[MAXSIZE];

            }else{

                  bits = new byte[(int)maxSize];

            }

      }

      public BitMap(int count) {

            bits = new byte[count];

      }

      /**

       * 添加数据元素,每一bit标识一个数据(0-不存在,1-存在)

       * @param i

       */

      public void add(long i){

            // 取模

            int r = (int)(i>>3);

            // 取余

            int c = (int)(i & 0x07);

            // | 或运算 只要一个为1,即为1

            if(contains(i)){

                  return;

            }

            bits[r] |=  (1 << c);

            count++;

      }

      /**

       * 验证数据是否存在

       * @param i

      * @return

       */

      public boolean contains(long i){

            // 取模

            int r = (int) (i>>3);

            // 取余

            int c = (int)(i & 0x07);

            // & 与运算 两个都为1,即为1

            if (((bits[r] >>> c) & 1) == 1) {

                  return true;

            }

           return false;

      }

      /**

       * 移除数据

       * @param i

       */

      public void remove(long i){

            // 取模

            int r = (int) (i>>3);

            // 取余

            int c = (int)(i & 0x07);

            if(!contains(i)){

                  return;

            }

            bits[r] &= ~(1 << c);

            count--;

      }

      /**

       * 获取数据记录总数 bit

       * @return

       */

      public long getCount(){

            return count;

      }

      /**

            * 获取下标元素数据,因为离散型数组存储,需要遍历全部数据

            * @param subscript

             * @return long

       */

      public long getNum(long subscript){

            long size = (long)bits.length<<3;

            long sub = 0;

            for(long i= 0;i < size;i++){

                 if(contains(i)){

                        if(sub == subscript){

                             return i;

                       }

                       sub++;

                 }

            }

            return 0;

      }

}

BitMap Bloom Filter扩展

注:布隆过滤器是以BitMap基本原理实现的扩展

布隆过滤器是一个含有 m 个元素的位数组(元素为0或1),每一位初始为0;并含有 k 个独立的哈希函数 h1, h2,..., hk 。

需要将集合中的元素加入到布隆过滤器中,依次计算h1(x), h2(x),...,hk(x),其计算结果填充对应数组的位置,并将其全部置1。一个位置可以被多次置1,但只有一次有效。

当查询某个元素是否在集合中时,计算这 k 个哈希函数,只有当其计算结果全部为1时,则认为可能存在;只要有1个计算结果为0时,则必不存在。

注:布隆过滤器存在假阳性的可能,即当所有哈希值都为1时,该元素也可能不在集合内,但该算法认为在里面。假阳性出现的概率被哈希函数的数量、位数组大小、以及集合元素等因素决定

BitMap Bloom Filter 优缺点与BitMap大致一样

  • 优点:

    • 空间效率高,所占空间小。
    • 查询时间短。
    • 自带去重
  • 缺点:
    • 元素添加到集合中后,不能被删除。
    • 有一定的误判率

布谷鸟过滤器与布隆过滤器比较

  1. 支持动态删除项;
  2. 更好的查找性能;
  3. 对于需要低假阳性率的应用程序(ϵ<3%)有更好的空间利用率

BitMap Bloom Filter 使用场景

  1. 大量数据中判断某个数据是否存在
  2. 解决缓存穿透
  3. 爬虫url/ 邮箱等系统的过滤

注:Bloom Filtet 实现请参考google,hutool

<dependency>

<groupId>com.google</groupId>

<artifactId>guava</artifactId>

<version>28.0-jre</version>

</dependency>

<dependency>

<groupId>cn.hutool</groupId>

<artifactId>hutool-all</artifactId>

<version>4.1.12</version>

</dependency>

BitMap数据结构梳理总结及代码实现相关推荐

  1. 数据结构梳理(6) - 图

    前言 这段时间偷懒了,上次二叉树写完之后,很长时间又没更新博客了,也没学啥东西,就一直咸鱼,所以今天赶紧脱离舒适区,继续把数据结构梳理完,目前为止,已经梳理了线性表.链表.栈.队列.二叉树,这次轮到图 ...

  2. 【Android 内存优化】Bitmap 硬盘缓存 ( Google 官方 Bitmap 示例 | DiskLruCache 开源库 | 代码示例 )

    文章目录 一.Google 官方 Bitmap 相关示例参考 二.磁盘缓存类 DiskLruCache 三.磁盘缓存初始化 四.存储数据到磁盘缓存中 五.从磁盘缓存中读取数据 六. Android 1 ...

  3. 如何梳理陌生的代码模块

    如何梳理陌生的代码模块 总体上可以遵循从整体到局部的方式.当然,不同的工作需要对代码梳理的程度不同,根据需要考量. 下面介绍梳理代码的维度: 1.明确模块的定位 在整个系统中处于什么位置:被谁调用,提 ...

  4. 数组数据结构的使用与代码编写(一)

    数组数据结构的使用与代码编写(一) 数组的使用 js中的数组 一.属性 1.length设置或返回数组元素的数目. 2.constructor返回构造函数的引用 var a=["a" ...

  5. 严蔚敏《数据结构》的全部代码实现(C语言)

    严蔚敏<数据结构>的全部代码实现(C语言)源码全部都在! http://u.115.com/file/f710d0eca1     提取码 f710d0eca1

  6. 【SA8295P 源码分析】05 - SA8295P QNX Host 上电开机过程 进一步梳理(结合代码)

    [SA8295P 源码分析]05 - SA8295P QNX Host 上电开机过程 进一步梳理(结合代码) 一.APPS PBL(Application Primary Boot Loader):固 ...

  7. 数据结构|考试大纲知识点梳理--自考课程代码02331 (2012年版)|计算机及应用(本科段)

    本文主要按照本书的考核知识点与考核要求,对每个章节的知识点分为识记.领会.简单应用.综合应用.重点五个层次进行梳理. 注:图中标有底色且为红色字体的,为该章的重点. 后续会按照自考考试大纲,发布计算机 ...

  8. 非常全面的Android Bitmap知识点梳理

    在日常开发中,可以说和Bitmap低头不见抬头见,基本上每个应用都会直接或间接的用到,而这里面又涉及到大量的相关知识. 所以这里把Bitmap的常用知识做个梳理,限于经验和能力,不做太深入的分析. 1 ...

  9. 【Android 内存优化】Bitmap 内存缓存 ( Bitmap 内存复用 | 弱引用 | 引用队列 | 针对不同 Android 版本开发不同的 Bitmap 复用策略 | 工具类代码 )

    文章目录 一.Bitmap 复用池 二.弱引用 Bitmap 内存释放 三.从 Bitmap 复用池中获取对应可以被复用的 Bitmap 对象 1.Android 2.3.3(API 级别 10)及以 ...

最新文章

  1. springboot 日志 log4j
  2. java 039 s rule_Java开发架构篇:DDD模型领域层决策规则树服务设计
  3. DPDK之makefile编译选项修改和gdb调试(三)
  4. Dalvik指令集 (smali汇编)
  5. Android 自定义View,自定义属性--自定义圆形进度条(整理)
  6. 利用for循环调用插入方法批量插入 一条失败_算法与数据结构(1):基础部分——以插入排序为例...
  7. java中使用okhttpsoap,Android okHttp网络请求之Retrofit+Okhttp+RxJava组合
  8. python语言网课答案_Python语言答案
  9. 修改图层的范围_PS教程连载第47课:PS图层操作案例星球
  10. 学python前要学c吗_目前python熟练 ,想再学golang 需要先学c吗?
  11. 【Java】Hello world
  12. 览沃livox_大疆览沃浩界(Livox Horizon)激光雷达测评
  13. python生成图文并茂的pdf--财务报表(三)--页面布局和排版
  14. 京东开始卖钻石了!?
  15. pwnable.kr第二遍---mistake
  16. echarts 地图自定义图标_echarts自定义图标的点击事件怎么添加
  17. 【MQTT基础篇(七)】MQTT主题
  18. scp 保留文件属组_scp传输文件的权限问题
  19. Windows窗口消息大全,全不全自己看
  20. zedgraph显示最小刻度_ZedGraph 控件各属性以及示例

热门文章

  1. 仿站后台路径怎么查找?
  2. java实现hj协议_HJ212协议java 实现 封装好的环保212协议代码 - 下载 - 搜珍网
  3. HJ卫星数据的下载与打开
  4. 基于北斗RDSS短报文的海洋浮标在线水质/气象综合监测系统
  5. tcpdump抓包使用小结
  6. C++入门之命名空间、缺省函数、重载函数及引用
  7. 微原实验三 基本IO口扩展
  8. 来自东南亚的极兔被“封杀”,老家还能保住吗?
  9. 【Linux学习-入门推荐】
  10. 基于android的电子书阅读器app