位图BiMap

在此记录我学的位图相关知识


是什么


是一种数据结构。也可以认为是一种二进制数组。
一个整型int是32位,用他的二进制能表示0-31这些整数是否出现过。

我们现在看int,要深入到微观去看,即看它的二进制,它有32个bit位

比如现在很多App上每月都有签到活动,一个月签到几次就送大礼包。这个功能我们就可以使用这种思想来实现。

 int calender; 用这一个整型来统计某个月的签到情况。
 

day 表示第几天
签到:即第day天签到了,则
int calender =0; 
calender |= (1 << (day & 31))//day表示第几天public void qiandao(int day){int calender =0;  // 00000000 00000000 00000000 00000000 calender |= (1 << (day & 31));System.out.println(calender);}@Testpublic void t1(){qiandao(2);//结果是 4。// 对应二进制  00000000 00000000 00000000 00000100// 说明第二天签到了}

一个整型数组int[ ] a = new int[32];

每个元素都是32位 ,  32*32= 1024。所以,这个数组能表示0-1023这些整数是否出现过。

相当于连起来了。

同理

一个long 是64位,能表示0-63数字是否出现过。

一个long数组 long[ ] b = new long[32], 32 * 64 = 2048 ,所以,这个数组能表示0-2047这些整数是
否出现过。

每一格子存储64个整数是否存在,a[0]可以表示0-64,a[1]可以表示64-127。返过来

126>>6 = 1(即126/64=1),即126落在a[1]里,又因为126 & 63=62(即126 % 64 = 62),所

以,具体来说是 a[1]的第62位表示126是否存在。

若存在,如何将该位设置为1?

使用 | 运算,即按位或运算。

1L 是long形的数字1,有64位,00000000000........000000001

1L << (126 &63) 然后 | 上a[1]

即 a[1] = a[1] | ( 1L << ( 125 & 63))

简写为 a[ 1 ] |= 1L << ( 125 & 63)

可以把数组每个元素看出一个桶。

把握关键点:添加时:

①确定该数 在数组中的哪个元素中(哪个桶中)--- /操作,用 >> 代替

②确定用 该元素的哪一位表示 ---- % 操作,用 &代替

为什么代替?因为位运算速度飞快

那如何删除呢?也很简单。使用 & ,用0 去和那个bit位进行 & 操作。

代码实现位图

看代码应该比较好懂。就是对二进制、位运算的一种巧妙应用。

public  class BitMap{public long[] bits;public BitMap(int max){//给定最大的数//若max=1,则数组长度得是1.若max=0,数组长度是1.抠边界。// >> 6 等价于 /64,但位运算速度更快bits = new long[(max+64) >> 6];}//num & 63 即num%64,看是该元素的第几位。public void add(int num){//两步:找到数组中对应的元素,然后,将相应位 弄成1. 必须写1L,表示是64位的1。//bits[num >> 6] = bits[num >> 6] | (1L << (num & 63));//简写为//bits[num >> 6 ]是确定在哪个桶里。num & 63 是确定在该桶的哪个位置,让1移动过去对准//每一个桶64位bits[num >> 6] |= (1L << (num & 63));}//删除public void delete(int num){bits[num >> 6] &= ~(1L << (num & 63));}public boolean contains(int num){return (bits[num >> 6] & (1L << (num & 63))) != 0;}
}

   带有测试的

public  class BitMap{public long[] bits;//给定一个预估的最大值,初始化数组,看看最多需要几个格子(几个坑位)//    如果实际业务中,超过了,那就重写造一个public BitMap(int max){//给定最大的数//若max=1,则数组长度得是1.若max=0,数组长度是1.抠边界。//看看最多需要几个格子。 >> 6 等价于 /64,但位运算速度更快bits = new long[(max+64) >> 6];}//num & 63 即num%64,看是该元素的第几位。public void add(int num){//两步:找到数组中对应的元素,然后,将相应位 弄成1. 必须写1L,表示是64位的1。//bits[num >> 6] = bits[num >> 6] | (1L << (num & 63));//简写为//bits[num >> 6 ]是确定在哪个桶里。num & 63 是确定在该桶的哪个位置,让1移动过去对准//把1怼上去//每一个桶64位bits[num >> 6] |= (1L << (num & 63));}//删除 // 这个好理解,就是先非一下,然后和他与,这样可以保证其他位置不变,只变标志位public void delete(int num){bits[num >> 6] &= ~(1L << (num & 63));}public boolean contains(int num){return (bits[num >> 6] & (1L << (num & 63))) != 0;//注意:是!=0, 它的结果不一定全是1}//1L << (num & 63) 相当于一个可以滑动的游标,一个辅助工具。public static void main(String[] args) {System.out.println("测试开始!");int max = 10000;BitMap bitMap = new BitMap(max);HashSet<Integer> set = new HashSet<>();int testTime = 10000000;for (int i = 0; i < testTime; i++) {int num = (int) (Math.random() * (max + 1));double decide = Math.random();if (decide < 0.333) {bitMap.add(num);set.add(num);} else if (decide < 0.666) {bitMap.delete(num);set.remove(num);} else {if (bitMap.contains(num) != set.contains(num)) {System.out.println("Oops!");break;}}}for (int num = 0; num <= max; num++) {if (bitMap.contains(num) != set.contains(num)) {System.out.println("Oops!");}}System.out.println("测试结束!");}}

什么用

当最大值确定时,就可以用位图收集数字,表示是否存在。好处是极大省空间。

搞牛逼一点,就是布隆过滤器,布隆过滤器就是使用 位图 + 多个哈希函数 实现的

位运算常识

a << 1 等价于 a*2

a<<2 等价于 a*4

a<<3 等价于 a*8

a<<4 等价于 a*16

a>>1 等价于 a/2

a >> 2 等价于 a/4

a>>3 等价于 a/8

a>> 4 等价于 a/16

a>>5 等价于 a/32

a>>6 等价于 a/64

a%64 等价于 a & 63,

a % n 等价于 a & (n-1),前提是 n必须是 2的k次幂,即n必须是 1、2、4、8、16、32、64、128...这样的数才行。

在JDK8的  HashMap源码里,二次哈希值对数组长度取模,得到索引。也用了这个操作,

hash & (length -1)

位运算的速度很快。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/149299.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

[软件工具]opencv-svm快速训练助手教程解决opencv C++ SVM模型训练与分类实现任务支持C# python调用

opencv中已经提供了svm算法可以对图像实现多分类&#xff0c;使用svm算法对图像分类的任务多用于场景简单且对时间有要求的场景&#xff0c;因为opencv的svm训练一般只需要很短时间就可以完成训练任务。但是目前网上没有一个工具很好解决训练问题&#xff0c;大部分需要自己编程…

网络安全的发展方向是什么?网络安全学什么内容

前言 不少小伙伴开始学习网络安全技术&#xff0c;但却不知道学习网络安全能找什么工作&#xff1f;网络安全是现下较为火热的职业岗位&#xff0c;吸引了许多企业和个人对网络安全技术的青睐。学习网络安全的人越来越多&#xff0c;网络安全也有很多发展方向。那么如何选择网…

《视觉 SLAM 十四讲》V2 第 5 讲 相机与图像

文章目录 相机 内参 && 外参5.1.2 畸变模型单目相机的成像过程5.1.3 双目相机模型5.1.4 RGB-D 相机模型 实践5.3.1 OpenCV 基础操作 【Code】OpenCV版本查看 5.3.2 图像去畸变 【Code】5.4.1 双目视觉 视差图 点云 【Code】5.4.2 RGB-D 点云 拼合成 地图【Code】 习题题…

【Linux】文件权限详解

&#x1f341; 博主 "开着拖拉机回家"带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——&#x1f390;开着拖拉机回家_Linux,Java基础学习,大数据运维-CSDN博客 &#x1f390;✨&#x1f341; &#x1fa81;&#x1f341; 希望本文能够给您带来一定的…

在word文档里面插入漂亮的伪代码

推荐用texsword.0.8 安装与界面 下载链接&#xff1a;https://sourceforge.net/projects/texsword/ 极为轻便&#xff0c;是Word的一个宏 安装过程也是极为简单&#xff0c;复制解压后的 texsword.dotm 文件到 C:\Users\{YOUR_USER_NAME}\AppData\Roaming\Microsoft\Word\ST…

分布式架构篇

1、微服务 微服务架构风格&#xff0c;就像是把一个单独的应用程序开发为一套小服务&#xff0c;每个服务运行在自己的进程中&#xff0c;并使用轻量级机制通信&#xff0c;通常是 HTTP API。这些服务围绕业务能力来构建&#xff0c;并通过完全自动化部署机制来独立部署。这些…

React框架核心原理

一、整体架构 三大核心库与对应的组件 history -> react-router -> react-router-dom react-router 可视为react-router-dom 的核心&#xff0c;里面封装了<Router>&#xff0c;<Route>&#xff0c;<Switch>等核心组件,实现了从路由的改变到组件的更新…

Ubuntu Server CLI专业提示

基础 网络 获取所有接口的IP地址 networkctl status 显示主机的所有IP地址 hostname -I 启用/禁用接口 ip link set <interface> up ip link set <interface> down 显示路线 ip route 将使用哪条路线到达主机 ip route get <IP> 安全 显示已登录的用户 w…

MySQL数据库单表查询

素材: 表名: worker-- 表中字段均为中文&#xff0c;比如 部门号 工资 职工号 参加工作 等 CREATE TABLE worker ( 部门号 int(11) NOT NULL, 职工号 int(11) NOT NULL, 工作时间 date NOT NULL, 工资 float(8,2) NOT NULL, 政治面貌 varchar(10) NOT NULL DEFAULT 群…

想要精通算法和SQL的成长之路 - 恢复二叉搜索树和有序链表转换二叉搜索树

想要精通算法和SQL的成长之路 - 恢复二叉搜索树和有序链表转换二叉搜索树 前言一. 恢复二叉搜索树二. 有序链表转换二叉搜索树 前言 想要精通算法和SQL的成长之路 - 系列导航 一. 恢复二叉搜索树 原题链接 首先&#xff0c;一个正常地二叉搜索树在中序遍历下&#xff0c;遍历…

Vue组件路由

1&#xff0c;安装vue-router组件&#xff0c;终端输入&#xff1a; npm i vue-router3.5.3 2&#xff0c;在src文件夹下创建router目录 3&#xff0c;创建index.js文件&#xff0c;配置路由&#xff0c;导入需要路由的组件。以后每次添加路由只要在routes中改变即可。 impo…

CTFHUB - SSRF

目录 SSRF漏洞 攻击对象 攻击形式 产生漏洞的函数 file_get_contents() fsockopen() curl_exec() 提高危害 利用的伪协议 file dict gopher 内网访问 伪协议读取文件 端口扫描 POST请求 总结 上传文件 总结 FastCGI协议 CGI和FastCGI的区别 FastCGI协议 …

如何查看postgresql中的数据库大小?

你可以使用以下命令来查看PostgreSQL数据库的大小&#xff1a; SELECT pg_database.datname as "database_name", pg_size_pretty(pg_database_size(pg_database.datname)) AS size_in_mb FROM pg_database ORDER by size_in_mb DESC;这将返回一个表格&#xff0…

一种4g扫码付费通电控制器方案

之前开发了一款扫码付款通电控制器 功能&#xff1a;用户扫码付款后设备通电&#xff0c;开始倒计时&#xff0c;倒计时结束后设备断电&#xff0c;资金到账商家的商家助手里面&#xff0c;腾讯会收取千分之6手续费。 产品主要应用场景 本产品主要应用于各类无人值守或者自助…

vmware安装centos8(三、centos的安装)

注意&#xff1a; 存放安装镜像文件的磁盘必须至少有128G的空间 1、在主界面左侧的客户机列表中选择”CentOS8“&#xff0c;在右侧选项卡中点击“开启此虚拟机”。 2、此对话框直接点击“确定” 3、当看到以下界面时&#xff0c;在虚机中中点击鼠标&#xff0c;使虚拟机捕获…

数据结构基本概念-Java常用算法

数据结构基本概念-Java常用算法 1、数据结构基本概念2、数据逻辑结构3、算法时间复杂度 1、数据结构基本概念 数据&#xff08;Data&#xff09;&#xff1a;数据是信息的载体&#xff0c;其能够被计算机识别、存储和加工处理&#xff0c;是计算机程序加工的“原材料”。数据元…

洛谷题目题解详细解答

洛谷是一个很不错的刷题软件&#xff0c;可是找不到合适的题解是个大麻烦&#xff0c;大家有啥可以私信问我&#xff0c;以下是我已经通过的题目。 你如果有哪一题不会&#xff08;最好是我通过过的&#xff0c;我没过的也没关系&#xff09;&#xff0c;可以私信我&#xff0…

数据结构和算法——数据结构

数据结构&#xff1a; 线性结构&#xff1a; 顺序存储方式&#xff0c;顺序表 常见的顺序存储结构有&#xff1a;数组、队列、链表、栈 链式存储方式&#xff0c;链表 队列&#xff1a; 队列可以使用数组结构或者链表结构来存储&#xff0c;先入先出&#xff0c;后进后出。…

jira 浏览器插件在问题列表页快速编辑问题标题

jira-issueTable-quicker 这是一个可以帮助我们在问题表格页快速编辑问题的浏览器插件 github 地址 功能介绍 jira 不可否认是一个可以帮助有效提高工作效率的工具&#xff0c;但是我们在使用 jira 时使用问题表格可以让我们看到跟多的内容而不用关注细节&#xff0c;但是目…

Rabbitmq安装-docker版

1.简介 2.安装消息队列 下载地址https://www.rabbitmq.com/download.html 使用docker方式安装 需要先下载docker&#xff0c;参考文章https://blog.csdn.net/weixin_43917045/article/details/104747341?csdn_share_tail%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22arti…