Python | BitMap算法及其实现
BitMap概述
本文介绍 BitMap 算法的应用背景,算法思想和相关实现细节。
概括而言,BitMap 主要用来解决海量数据中元素查询,去重、以及排序等问题。这里对海量数据场景的强调,似乎暗示了这个算法对空间的利用相当的精巧和经济,事实确实如此。
BitMap算法
本来数据序列的排序是一个平凡的任务,现有的多种排序算法,都有各自擅场能适应不同情形的具体要求。但我们考虑这样一个场景:有一台内存为 4 GB 的 PC,其硬盘中的一个存储了 30 亿个无符号整型数据文件,这些整数一行一个且无重复。现在需要我们对这个文件中的数据进行排序后输出。
简单计算不难得到,这个数据文件的大小为 \(4⋅3⋅10^9/2^{30}\) 约为 11.2 GB,显然将这个数据文件直接读入内存是办不到的。能否强行利用现有的内存 size 来存储这些数据呢?答案是可能的,此时 BitMap 算法就该 C 位亮相了。BitMap 的想法相当精妙,它对整型数据作了一种转化,使得这个办不到的存储成为可能。我们这里忽略不同语言的设定,假设一个 int 整数占 4 个字节,即32 bit,如果我们能用一个 bit 位来标示一个 int 整数,那么需要的存储空间将大大减少,估算一下可知,30亿个整数需要的内存空间为 \(4⋅3⋅10^9/8/2^{20}\) 大概为 357.6 MB,这样,我们可以轻易将这 30 亿个 int 数放到内存中进行处理。
具体而言,BitMap 对数据的转化可简述如下:
一个整型 int 占 4 bytes,共32位,我们申请一个 int 长度为 N//32 + 1 的数组,即可存储完这些数据,其中 N 表示要进行查找的最大整数,这可以经读取遍历一轮数据获得。通过数组中的每个元素在内存在占 32 位对应表示十进制数 0-31,故可得到 BitMap 表:
array[0] 可表示 0-31
array[1] 可表示 32-63
array[2] 可表示 64-95
...
下面就只剩下如何将十进制数转换为对应的二进制 bit 位,实现以 1 当 32 的效果,显然,这部分实现只需用到一些位运算操作,具体细节见下面的代码示例。不难看出,Bitmap 排序需要的时间复杂度和空间复杂度依赖于数据中最大的数字。
代码实现
from array import array
class BitMap:
def __init__(self):
self.n = 5
self.bitsize = 1 << self.n
self.typecode = 'I' # 32位unsighed整型
self.lowerbound = 0 # 若数组中有负数,则所有数都减去最小的那个负数
@staticmethod
def greater_power2n(x):
i = 1
while True:
y = x >> i
x |= y
if y == 0:
break
i <<= 1
return x + 1
def load(self, inp):
'''
一般情形,数据应该是流式读取,这里简化起见不失一般性,将数据直接全部读完
'''
mini = min(inp)
if mini < 0:
self.lowerbound = -mini # 如果数组中有<0的数,则所有数都要减去最小的那个负数
inp = [i + self.lowerbound for i in inp]
maxi = max(inp)
num_arr = max(self.greater_power2n(maxi) >> self.n, 1) # 至少应该使用一个数组
self.arr = array(self.typecode, [0] * num_arr)
for x in inp:
self._set(x)
def _set(self, x, set_val=True):
'''
将x在数组中对应元置为1
'''
arr_idx = x >> self.n # 元素在第几个数组中,等价于x // 2**self.n
bit_idx = x & (self.bitsize - 1) # 元素在相应数组中的第几个bit位,等价于x % 2**self.n
if set_val:
self.arr[arr_idx] |= 1 << bit_idx
else:
self.arr[arr_idx] &= ~(1 << bit_idx)
def search(self, x):
if self.lowerbound != 0:
x += self.lowerbound
arr_idx = x >> self.n
bit_idx = x & (self.bitsize - 1)
existence = True if self.arr[arr_idx] & (1 << bit_idx) else False
return existence
def sort(self):
sorted_seq = []
for arr_idx, a in enumerate(self.arr):
for bit_idx in range(self.bitsize):
if a & (1 << bit_idx):
sorted_seq.append(arr_idx * self.bitsize + bit_idx - self.lowerbound)
return sorted_seq
def show_bitmap(self):
for i, a in enumerate(self.arr):
print('The {}th array elements: {:032b}'.format(i, a))
运行测试
>>> bitmap = BitMap()
>>> bitmap.load([-3, 2, 56, -34, 40, 21, 99, 25])
>>> bitmap.search(21), bitmap.search(3)
(True, False)
>>> bitmap.sort()
[-34, -3, 2, 21, 25, 40, 56, 99]
参考资料
黑胡同里の猫,详解BitMap算法,https://www.520mwx.com/view/59057
位图算法及其实现,BitMap,https://www.pythonf.cn/read/84436
Python | BitMap算法及其实现的更多相关文章
- BitMap算法及其实现(Python)
BitMap概述 本文介绍 BitMap 算法的应用背景,算法思想和相关实现细节. 概括而言,BitMap 主要用来解决海量数据中元素查询,去重.以及排序等问题.这里对海量数据场景的强调,似乎暗示了这 ...
- BitMap算法知识笔记以及在大数据方向的使用
概述 所谓的BitMap算法就是位图算法,简单说就是用一个bit位来标记某个元素所对应的value,而key即是该元素,由于BitMap使用了bit位来存储数据,因此可以大大节省存储空间,这是很常用的 ...
- Python基础算法综合:加减乘除四则运算方法
#!usr/bin/env python# -*- coding:utf-8 -*-#python的算法加减乘除用符号:+,-,*,/来表示#以下全是python2.x写法,3.x以上请在python ...
- BitMap算法应用:Redis队列滤重优化
工作中有用到Redis滤重队列. 原来的方法如下: 方法一 为了保证操作原子性,使用Redis执行Lua脚本. 在脚本中的逻辑是,如果队列不超过某个数值,进行一次lrem操作(队列使用list结构), ...
- bitmap算法
概述 所谓bitmap就是用一个bit位来标记某个元素对应的value,而key即是这个元素.由于采用bit为单位来存储数据,因此在可以大大的节省存储空间 算法思想 32位机器上,一个整形,比如int ...
- xsank的快餐 » Python simhash算法解决字符串相似问题
xsank的快餐 » Python simhash算法解决字符串相似问题 Python simhash算法解决字符串相似问题
- 经典算法题每日演练——第十一题 Bitmap算法
原文:经典算法题每日演练--第十一题 Bitmap算法 在所有具有性能优化的数据结构中,我想大家使用最多的就是hash表,是的,在具有定位查找上具有O(1)的常量时间,多么的简洁优美, 但是在特定的场 ...
- BitMap 算法
什么是 BigMap 算法 所谓 BitMap 就是用一个 bit 位来标记某个元素对应的 value,而 key 即是这个元素.由于采用bit为单位来存储数据,因此在可以大大的节省存储空间. 算法思 ...
- 【算法与数据结构专场】BitMap算法基本操作代码实现
上篇我们讲了BitMap是如何对数据进行存储的,没看过的可以看一下[算法与数据结构专场]BitMap算法介绍 这篇我们来讲一下BitMap这个数据结构的代码实现. 回顾下数据的存储原理 一个二进制位对 ...
- 浅谈bitmap算法
一.bitmap算法思想 32位机器上,一个整形,比如int a; 在内存中占32bit位,可以用对应的32bit位对应十进制的0-31个数,bitmap算法利用这种思想处理大量数据的排序与查询. ...
随机推荐
- 如何通过C++ 给PDF文档添加文字水印
因PDF文档具有较好的稳定性和兼容性,现在越来越多的合同.研究论文.报告等都采用PDF格式.为了进一步保护这些重要文档内容免受未经授权的复制或使用,我们可以添加水印以表明其状态.所有权或用途.针对工作 ...
- IDEA提示java_ 程序包org.apache.ibatis.session不存在
一.解决方案 1.问题原因: 这是因为配置Java的程序包这块出现了错误,同时可能你还没有设置让IDEA自动加载Jar包,才会报出这种错误的. 2.解决方案: 解决方式如下: File->Set ...
- jmeter-逻辑处理器while
测试工具:jmeter 业务逻辑:A接口上传文件,B接口查询文件上传状态,如果状态不为4,需要再次查询(上传文件后,需要有短暂时间的识别,压测时并发大导致识别时间不可控)当为4时,跳出循环, 思路:增 ...
- 神经网络入门篇:详解参数VS超参数(Parameters vs Hyperparameters)
参数 VS 超参数 什么是超参数? 比如算法中的learning rate \(a\)(学习率).iterations(梯度下降法循环的数量).\(L\)(隐藏层数目).\({{n}^{[l]}}\) ...
- ElasticSearch索引生命周期策略配置(ES TTL)
背景 有些索引数据作为临时数据存放,一段时间后我们希望索引可以自动过期删除,就是常说的TTL(Time To Live)机制 ElasticSearch索引数量过多会占用很多主分片和副本分片,最终导致 ...
- Scrapy框架架构
ENGINE:引擎,负责各个组件的管理. SPIDERS:各个爬虫文件类.(我们一般要写的代码就是这个). SCHEDULER:调度器,ENGINE将爬虫任务分发给该组件,由该组件调度爬虫任务. DO ...
- Javascript Ajax总结——GET请求和POST请求
1.GET请求GET最常用于向服务器查询信息.可在URL末尾添加查询字符串参数.XHR中,传入open()方法的URL末尾的查询字符串必须经过正确的编码,使用encodeURIComponent()编 ...
- 【笔记】Ribbon负载均衡伪随机算法
伪随机:思路 当一个下标(伪服务)连接被调用两次,第三次如果还是它,就让再随机一次 当重复随机到一台服务两次时判断第三次是否还是它 是的话 我们要进行 再次随机 也就是第三次 package top. ...
- vulntarget-d-wp
vulntarget-d 配置信息 系统 ip kali 192.168.130.5 ubuntu 18 ip1: 192.168.130.8 ip2: 10.0.10.1 win7 10.0.10. ...
- CentOS7 安装Python3.9以上版本时。编译报错,原因是openssl版本低
openssl-1.1.1安装 1.前因 python 导入clickhouse_driver需要import ssl和_ssl,报错 File"/home/oracle/python3/l ...