1. 初识 Bitmap

Bitmap 也被称为位图。Bitmap 既是一种数据结构,又是一种图片类型。从数据结构的角度讲,Bitmap 适用于以下场景,后文会逐一进行阐述:

  1. 判重
  2. 定基
  3. 排序
  4. 压缩

2. 数据结构

Bitmap 是指由多个二进制位组成的数组,数组中的每个二进制位都有与其对应的索引。可以使用索引对二进制位进行操作。如下图表示 16 位的 Bitmap:

数据 {0, 4, 9, 10, 13} 存入 Bitmap 如图2 所示:

判重

判重是指一个元素是否在一个数据集中是否重复出现或存在。在数据处理领域,判重是个很常见的需求。搬个网上的栗子:给一台普通 PC,2G 内存,要求处理一个包含 40 亿个不重复并且没有排过序的无符号的 int 整数,给出一个整数,问如何快速地判断这个整数是否在文件 40 亿个数据当中?

分析:如果我们用 Java 的整型来存储,一个整型是 4Byte,那么 40 亿个 int 需要 40亿 * 4 / 1024 / 1024 / 1024 = 14.9GB。这谁受得了,2GB 内存显然放不下啊。如果采用 Bitmap 存储,那么 40 亿个 int 需要 40 / 1024 / 1024 = 476.84MB,这样就可以放到内存里进行计算了。这里用两种方法可以处理:

  1. 很多语言如 Java、C++ 都有现成的 Bitmap 数据结构,索引即 int 整数,索引对应的值即该是否存在,即是否重复。
  2. 用 int[] 数组,每个索引元素表示 4Byte * 8 = 32bit,int 整数除以 32 的结果表示 int[] 数组的索引 Index,int 整数对 32 取模的结果表示 int[] 数组在索引 Index 上所在的偏移量。

定基

定基是指一个数据集中存在多少不同的元素,即数据集的基数。举个栗子:某网站有 15 亿用户,用户 ID 在 1,000,000,000~2,999,999,999 之间,统计每天登陆了多少个用户,最多有 256MB 的内存空间可用。

分析:采用 Bitmap,首先将用户 ID 减去 10^10 ,用 1,999,999,999 个 bit 位存储需要 20亿 / 8 / 1024 / 1024 = 238.42MB 小于 256MB。然后将 Bitmap 的二进制索引一一映射(出现过即设置为 1),最后遍历计算出 Bitmap 中 1 的个数即可。

排序

排序就不做赘述了。直接上栗子:一个最多包含 n 个正整数的文件,每个数都小于 n,其中 n = 10^7,且所有正整数都不重复。最多有 2MB 的内存空间可用,求如何将这 n 个正整数升序排列。

分析:采用 Bitmap,10,000,000 / 1024 / 1024 = 1.19MB,2MB 绰绰有余了。存到 Bitmap 里之后(正整数出现过设置为 1),则遍历 Bitmap 遇到 bit 位是 1 时,输入索引即可。

3. 压缩

Bitmap 可以压缩数组,对象或任何类型的数据。我们现在使用 JSON 将大型数组从服务器传输到客户端(浏览器)。假设现在我们有一个数据集,包含了一组不同的年份,并且以不同的方式分散。

data = {0   => 1991,1   => 1992,2   => 1993,3   => 1994,4   => 1991,5   => 1992,6   => 1993,7   => 1992,8   => 1991,9   => 1991,10  => 1991,11  => 1992,12  => 1992,13  => 1991,14  => 1991,15  => 1992,...
}

这个 JSON 将编码的信息如下:

[1991,1992,1993,1994,1991,1992,1993,1992,1991,1991,1991,1992,1992,1991,1991,1992, ...]

如果我们采用 Bitmap 去编码,会得到一个很短的数组:

data = (0 => array(1991, '1000100011100110'),1 => array(1992, '0100010100011001'),2 => array(1993, '0010001000000000'),3 => array(1994, '0001000000000000'),
)

最后,JSON 压缩之后的结果如下:

[[1991,"1000100011100110"],[1992,"0100010100011001"],[1993,"0010001000000000"],[1994,"0001000000000000"]
]

显而易见,压缩之后的效果会比未压缩要好很多。事实上,我们大多数人都知道图像的位图压缩,因为该算法主要用于图像压缩。 我们可以想象压缩黑白图像时会多么成功(因为黑白可以表示为 0 和 1)。 实际上,Bitmap 用于两种以上的颜色(例如256种),其压缩级别也是很高的。

4. 位图图像

每张图片按大小来存储,即图像的长宽像素大小。如果一张图片的像素是 100 × 100 100 \times 100 100×100,则此图像在内存的存放是一个 100 × 100 100 \times 100 100×100 的数组,每个数组的元素是 int 整型(整数占用 4 个 byte )。

数组中每个元素中整型数字含四位信息:RGBA。RGB 就是自然界三原色,通过 RGB 的组合可以将任何色彩表示出来。

  1. R:Red 红色通道(占一个 byte 取值 0~255)
  2. G:Green 绿色通道色(占一个 byte 取值 0~255 )
  3. B:Blue 蓝色通道(占一个 byte 取值 0~255 )
  4. A:Alpha 通道值,即该位置像素点的透明值(占一个 byte 取值 0~255)

举个栗子,下面的数组表示这是一张 4 × 4 4 \times 4 4×4 像素大小的全红色的图。一个像素在屏幕上显示出来非常小,当多个不同的像素按规律摆放在一起形成有行有列的数组的时候,我们就看到了图像。

{{0xffff0000,0xffff0000,0xffff0000,0xffff0000},{0xffff0000,0xffff0000,0xffff0000,0xffff0000},{0xffff0000,0xffff0000,0xffff0000,0xffff0000},{0xffff0000,0xffff0000,0xffff0000,0xffff0000}
}

在掘金上面看到了这样一个面试题:100*100 的 canvas 占多少内存?作者的解释如下:

我们在定义颜色的时候就是使用 rgba(r,g,b,a) 四个维度来表示,而且每个像素值就是用十六位 00-ff 表示,即每个维度的范围是 0~255,即 2^8 位,即 1 byte, 也就是 Uint8 能表示的范围。所以 100 * 100 canvas 占的内存是 100 * 100 * 4 bytes = 40,000 bytes。

5. 扩展:数码相机的图片

我们通常说的图片分辨率其实是指像素数,表示长度方向的像素点数乘以宽度方向的像素点数。由于数码图片没有物理上的长宽概念,而数码图片的长宽也并非物理的长度单位,是指各自方向上的像素点数。

比如,数码相机支持 500 万像素,一般是指 25921944 或 25601920,其中第一个数字表示图片长度方向上所包含的像素点数,第二个数字表示其宽度方向上所包含的像素点数。二者的乘积 25921944 = 5038848,25601920 = 4915200,都约等于 500 万(像素)。500 万像素代表它能处理多大的图形色彩信息的能力,像素越高,需要处理时间越长,因为数组很大。

500 万像素,就是由 500 万个这样的方块或者点组成,而且像素点的尺寸是不一定的。

数码图片的计算大小和实际大小

一台 500 万像素的数码相机拍摄的图片,这张图片的实际容量是 500万 X 3= 1500万 = 15MB ,乘以 3 是因为数码相机中的感光 CCD 是通过红、绿、蓝三色通道,所以最终图像容量就要乘以 3。

但是数码图片的实际大小会和内存大小不同,实际大小与图片采用的存储文件格式、文件头和附加信息有关。

6. Bitmap 的实现

JDK 源码中 Bitmap 是用 long[] 实现的,为了和第 3 节相对应,我们采用 int[] 实现。一个 int 整型占 4byte、32bit:

bitmap[0]  00000000000000000000000000000000      bit位区间:[0, 31]
bitmap[1]  00000000000000000000000000000000     bit位区间:[31, 63]
......

对于第 N (从 0 开始)个 bit 位在 int[] 中的计算方法如下:

  1. N/32:表示 int[] 的下标索引 IDX;
  2. N%32:表示 int[IDX] 中的偏移量。

在实现的时候,有人给出了位运算的方案,实现比较优雅,指定的 Bitmap 的 bit 位 N(从 0 开始):

  1. N >> 5:表示 int[] 的下标索引 IDX;
  2. N & 31:表示 int[IDX] 中的偏移量。
public class BitMap {private int[] words;public BitMap(long capacity) {// 计算words的下标索引int arrayIndex = (int) (capacity >> 5);// 计算words[arrayIndex]的偏移量int offset = (capacity & 31) > 0 ? 1 : 0;this.words = new int[arrayIndex + offset];}/*** @param index ∈ [0, capacity)*/public void set(long index) {int arrayIndex = (int) (index >> 5);int offset = (int) (index & 31);words[arrayIndex] |= (0x01 << offset);}/*** @param index ∈ [0, capacity)*/public int get(long index) {int arrayIndex = (int) (index >> 5);int offset = (int) (index & 31);return words[arrayIndex] >> offset & 0x01;}
}

扫码关注公众号:冰山烈焰的黑板报

数据算法: Bitmap相关推荐

  1. 货拉拉大数据对BitMap的探索与实践(上)

    1. 引言 在大数据时代,想要不断提升基于海量数据获取的决策.洞察发现和流程优化等能力,就需要不停思考,如何在利用有限的资源实现高效稳定地产出可信且丰富的数据,从而提高赋能下游产品的效率以及效果.在货 ...

  2. 大数据算法python_闲谈大数据和算法

    0x00 前言 本篇总结一下自己对大数据算法认知的过程.正文包含两部分:自己对算法的认知过程和对大数据算法的理解. 写这篇博客的原因有很多,总的来讲有下面几点: 自己在算法的路上一直懵懵懂懂,现在刚刚 ...

  3. 智源杯天文数据算法挑战赛开赛,前沿AI技术助力天文科学研究

    由北京智源人工智能研究院主办,国家天文台.数据评测平台biendata联合举办的天体分类数据竞赛于2020年1月开赛.本次比赛旨在鼓励大众参与到天文学的探索当中,利用最新的人工智能算法分析望远镜收集到 ...

  4. 大数据算法系列——布隆过滤器

    大数据算法系列--布隆过滤器 一.简介 Bloom filter介绍 Bloom Filter(BF)是一种空间效率很高的随机数据结构,它利用位数组很简洁地表示一个集合,并能判断一个元素是否属于这个集 ...

  5. 《大数据算法》一1.2 大数据算法

    本节书摘来华章计算机<大数据算法>一书中的第1章 ,第1.2节,王宏志 编著, 更多章节内容可以访问云栖社区"华章计算机"公众号查看. 1.2 大数据算法 这一节我们概 ...

  6. 神策数据算法专家:推荐系统的实践与思考(下)

    本文内容来自神策数据<智能推荐--应用场景与技术难点剖析>闭门会分享内容整理,分享者为神策数据算法专家胡士文,分享主题为<推荐系统的实践与思考>,前面我们介绍了算法和数据部分( ...

  7. 神策数据算法专家:推荐系统的实践与思考(上)

    本文内容来自神策数据<智能推荐--应用场景与技术难点剖析>闭门会分享内容整理,分享者为神策数据算法专家胡士文,分享主题为<推荐系统的实践与思考>. 大家好,在演讲开始前,我对在 ...

  8. PPT 下载 | 神策数据算法专家:推荐系统的实践与思考(下)

    本文内容来自神策数据<智能推荐--应用场景与技术难点剖析>闭门会分享内容整理,分享者为神策数据算法专家胡士文,分享主题为<推荐系统的实践与思考>,前面我们介绍了算法和数据部分( ...

  9. PPT 下载 | 神策数据算法专家:推荐系统的实践与思考(上)

    本文内容来自神策数据<智能推荐--应用场景与技术难点剖析>闭门会分享内容整理,分享者为神策数据算法专家胡士文,分享主题为<推荐系统的实践与思考>. 大家好,在演讲开始前,我对在 ...

最新文章

  1. 单例模式 之 单例模式——枚举
  2. java中如何将非整数保留到小数点后指定的位数
  3. php8vsgo,vscode编辑好go语言代码要怎么运行
  4. ICMP:Internet控制报文协议
  5. 北林oj-算法设计与分析-Tom palindrome number
  6. Java数据库表自动转化为PO对象
  7. 非常简单的conda环境重命名方法
  8. No package ‘glib-2.0‘ found/No package ‘gobject-2.0‘ found
  9. Linux笔记(一)——虚拟机的安装与Centors安装,安装vmtools,虚拟机的克隆,虚拟机的快照,共享文件的使用
  10. moodle php代码解读_Moodle插件开发笔记
  11. win7 局域网服务器 文件共享,Win7系统电脑设置局域网共享文件的操作方法-电脑自学网...
  12. vb rs.RecordCount返回0的原因
  13. SSL证书的概念、作用及分类、价格介绍
  14. 苹果关闭iOS 16.1.2 验证通道,iPhone升级 iOS 16.2 后无法降级
  15. matlab学霸表白公式,学霸隐藏式表白数学公式
  16. 微信 Emoji表情代码大全
  17. 半年以来的图像去雾总结-图像去雾(一)暗通道去雾
  18. 无接任何usb设备却提示无法识别usb设备
  19. python提取数列数字_从pandas datafram中的列中提取字符串中的数字
  20. 那些年我记下的一些编程错误

热门文章

  1. vs2017 安装XNA
  2. python中logger_python中的logger
  3. android系统提供的几种颜色Color
  4. reimu hakurei
  5. 硬件课程设计:基于STM32的多功能播放器之小游戏
  6. 使用阿里云短信服务测试功能发送短信到手机验证
  7. python爬虫获取元素的属性值_趣说Python爬虫05--获取基金实时净值
  8. C#编程-36:数组与ArrayList基础复习_彭世瑜_新浪博客
  9. c语言之格式控制字符与输入输出函数
  10. 【读书笔记】《再造卓越》吉姆•柯林斯