高效查找秘密武器一:位图

有这样的一个问题:

给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在这40亿个数 中。

那么我们一般会想到这样做的

1.遍历,时间复杂度O(n)

2.排序(N*logN),然后二分查找

那么此时此刻,我们再次细想一下,这些方法一般放在内存中进行的,那么40亿个不重复的无符号整数,有多大容量呢?

首先,10亿个字节大概是1个G

那么10亿个整数大约是4个G

然后呢40亿个整数大约是16个G

所以,如若这么大容量放到电脑内存上跑,恰好此时电脑内存也是16个G,那么不是刚刚好?

其实不然,电脑上不单单只是跑这个程序,后面还有很多,比如微信啊,爱奇艺什么的,所以一般来说,这么大容量放到16G的电脑内存是不太现实的。

那么还有什么解决办法呢?

那就请出今天的主角之一:位图

位图

那么什么又是位图呢?
这里说的位图指的是数据结构当中的,不是那个指图像那个位图哦!

位图:所谓的位图,就是用每一位来存放某种状态的。

适用于海量数据,整数,数据无重复的场景。通常用来判定某个数据存不存在的。

那么举个例子来看看

我这里,假设有了一个字节数组,然后有三个字节,那么一个字节呢,又对应8个比特位

一个比特位呢,又可以代表0/1两种状态。

所以数组arr中,每个数字可以通过某个算式来确定某个位置,然后将某个位置的比特位设置为1,说明,此数字存在。

比如,就11来说

11/8=1

那么我们就放到这个1下标

11%8=3

那么我们就在数组1下标下的第三个比特位设置为1,

然后可以说明数字是存在过的

这里值得注意下,为什么比特位标明的数字从右到左呢?

这里是为了方便,自己也是可以左到右的。

那么回过头细想一下,一个字节有8个比特位,且8个比特位都可以表示状态。

那么10亿个字节大概是0.9G,接近1G

10亿个比特位大概是119兆,看作128兆

那么40亿个比特位,那么就是可以看作512兆。

所以内存量一下子大大缩小了。

那么你看这个位图是不是很强大呢!

ok,那么接下来讲讲如何实现它吧。

由上述刚刚的例子可以看得出,底层还是一个数组来的,而且还是一个字节数组。

然后呢,我们创建它的时候,默认给定一个容量。

但是,有时候,需要用户指定它需要范围是多大,那么可以这样写。

  //位图底层还是一个数组public byte [] elem;//记录存放数据多少public int Usize;public MyBitMap(){//默认给定的数组大小是1个字节this.elem=new byte[1];}public MyBitMap(int n){this.elem=new byte[n/8+1];}

在给定参数的构造方法中,假设我们给定数字范围是10个,那么10/8=1,但是还余下两个,9 10

所以我们直接给多一个字节是可以的。set

那么接着讲讲set吧

set:

思路:

当然这是核心思路,然后代码实现方面还是需要考虑一些细节

比如,我们set方法,参数传入一个数字的话,如若数字给到的是<0的数字,那么此时是不符合我们位图的

再者如果是给定的数字,如若在找数组下标时超出数组范围,这时候也是需要处理的,比如扩容操作。

那么代码如下:

 public void set(int val){if(val<0){//需要抛出异常,因为会导致数组越界throw new IndexOutOfBoundsException();}//放到字节数组哪个位置int arrIndex=val/8;if(arrIndex>elem.length){//超出数组范围,进行扩容elem= Arrays.copyOf(elem,arrIndex+1);}//放到字节数组位置的哪个比特位int bitIndex=val%8;elem[arrIndex] |=(1<<bitIndex);Usize++;}

这个找哪个比特位进行修改,其实最开始时讲过了

即val/8=字节数组哪个下标,

val%8=下标内哪个比特位。

所以这里我们就可以找到,哪个字节哪个比特位要进行修改状态,比如举的例子,设置5这个数字

5/8=0,即在数组0下标

5%8=5,即在比特位第六个位置

get:

这个get方法是返回这个数字是否是存在过的。

所以呢,我们还得是找到这个数字在哪先,然后判断下这个数字的比特位是否是1

举例:

代码:
 

public boolean get(int val){if(val<0){throw new IndexOutOfBoundsException();}int arrIndex=val/8;int bitIndex=val%8;if((elem[arrIndex]&(1<<bitIndex))!=0){return true;}return false;}

reset:

reset方法呢,是把传入参数,对应的比特重新置为0

举例说明:

代码:

 public void reset(int val){if(val<0){throw new IndexOutOfBoundsException();}int arrIndex=val/8;int bitIndex=val%8;elem[arrIndex] &= ~(1<<bitIndex);Usize--;}public int getSize(){return Usize;}

值得注意的是,进行set的时候,Usize++了

所以写一个方法方法来返回当前设置的个数。

那么位图一些基本方法写完了,这里还差最后一个方法:排序

排序

其实我们位图是可以排序的

拿这里来说:

只要我们从右边开始,遍历当前比特位是1的就可以输出当前的值

那么判断当前位是不是为1,是get方法里的思路是一致的,用上&

那么如何输出当前的数字呢?

比如我要输出的是5,那么此时我们可以这样val=i*8+j

当前的i=0,因为我们输出的数字是5,在字节数组的0下标,当j从下标开始遍历,j=5时,就可以输出这个数字5了

代码:
 

 public static void main(String[] args) {int [] arr=new int[]{3,10,9,5,7,24,18};MyBitMap myBitMap=new MyBitMap(24);//先把数据放进字节数组中for(int i=0;i<arr.length;i++){myBitMap.set(arr[i]);}//排序for(int i=0;i< myBitMap.elem.length;i++){for(int j=0;j<8;j++){if((myBitMap.elem[i]&(1<<j))!=0){System.out.print(i*8+j+" ");}}}}

ok,那么位图这里,小编分享的差不多了。

顺带提一句,一开始给的那道题是腾讯曾经的面试题来的。

源码:

public class MyBitMap {//位图底层还是一个数组public byte [] elem;//记录存放数据多少public int Usize;public MyBitMap(){//默认给定的数组大小是1个字节this.elem=new byte[1];}public MyBitMap(int n){this.elem=new byte[n/8+1];}/*** set操作,对添加进来的数据置为1,即为存在的意思* @param val*/public void set(int val){if(val<0){//需要抛出异常,因为会导致数组越界throw new IndexOutOfBoundsException();}//放到字节数组哪个位置int arrIndex=val/8;if(arrIndex>elem.length){//超出数组范围,进行扩容elem= Arrays.copyOf(elem,arrIndex+1);}//放到字节数组位置的哪个比特位int bitIndex=val%8;elem[arrIndex] |=(1<<bitIndex);Usize++;}/*** get方法返回比特位是否设置过1* @param val* @return*/public boolean get(int val){if(val<0){throw new IndexOutOfBoundsException();}int arrIndex=val/8;int bitIndex=val%8;if((elem[arrIndex]&(1<<bitIndex))!=0){return true;}return false;}public void reset(int val){if(val<0){throw new IndexOutOfBoundsException();}int arrIndex=val/8;int bitIndex=val%8;elem[arrIndex] &= ~(1<<bitIndex);Usize--;}public int getSize(){return Usize;}public static void main(String[] args) {int [] arr=new int[]{3,10,9,5,7,24,18};MyBitMap myBitMap=new MyBitMap(24);//先把数据放进字节数组中for(int i=0;i<arr.length;i++){myBitMap.set(arr[i]);}//排序for(int i=0;i< myBitMap.elem.length;i++){for(int j=0;j<8;j++){if((myBitMap.elem[i]&(1<<j))!=0){System.out.print(i*8+j+" ");}}}}
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《单片机原理及接口技术》(C51编程)(第三版)------张毅刚主编

1.整体框架&#xff1a;1-22题&#xff08;17-20为编程题分别源自数中的P98,P162,P177页&#xff09; 2.简答题部分&#xff1a; 3.计算题 4.程序题/编程题

Vision Transformer (ViT) 基本原理

Vision Transformer (ViT) 基本原理 flyfish Vision Transformer (ViT) 是一种基于 Transformer 架构的计算机视觉模型 一、ViT 的基本原理 ViT 的核心思想是将一张图像视为一组序列&#xff0c;将其嵌入到 Transformer 的输入中&#xff0c;通过自注意力机制捕获全局上下文…

工业异常检测-CVPR2024-新的3D异常数据合成办法和自监督网络IMRNet

论文&#xff1a;https://arxiv.org/pdf/2311.14897v3.pdf 项目&#xff1a;https://github.com/chopper-233/anomaly-shapenet 这篇论文主要关注的是3D异常检测和定位&#xff0c;这是一个在工业质量检查中至关重要的任务。作者们提出了一种新的方法来合成3D异常数据&#x…

三款电容麦的对比

纸面参数 第一款麦克风 灵敏度: -36 dB 2 dB&#xff08;0 dB1V/Pa at 1 kHz&#xff09; 灵敏度较低&#xff0c;需要更高的增益来拾取同样的音量。频率响应: 40 Hz - 18 kHz 响应范围较窄&#xff0c;尤其在高频区域。等效噪音级: ≤18 dB&#xff08;A计权&#xff09; 噪…

easyexcel 导出日期格式化

1.旧版本 在新的版本中formate已经被打上废弃标记。那么不推荐使用这种方式。 2.推荐方式 推荐使用另外一种方式【 Converter 】代码如下&#xff0c;例如需要格式化到毫秒【yyyy-MM-dd HH:mm:ss SSS】级别 创建一个公共Converter import com.alibaba.excel.converters.Conv…

PPT怎样做的更加精美

目录 PPT怎样做的更加精美 3D的GIF图片 3维空间图​编辑 结果有明显的对比 阅读高质量文献,采用他们的图 PPT怎样做的更加精美 3D的GIF图片 3维空间图 结果有明显的对比

插入排序⁻⁻⁻⁻直接插入排序希尔排序

引言 所谓的排序&#xff0c;就是使一串记录按照其中的某个或某些关键字的大小&#xff0c;递增或递减的排列起来的操作。 常见的排序算法有&#xff1a; 今天我们主要学习插入排序的直接插入排序和希尔排序。 直接插入排序 什么是直接插入排序&#xff1f; 直接插入排序其…

鸿蒙UI开发——亮/暗色模式适配

1、概 述 系统存在深浅色两种显示模式&#xff0c;为了给用户更好的使用体验&#xff0c;应用最好适配暗色和亮色两种模式。从应用与系统配置关联的角度来看&#xff0c;适配暗色和亮色模式可以分为下面两种情况&#xff1a; 应用跟随系统的深浅色模式&#xff1b; 应用主动设…

推荐在线Sql运行

SQL Fiddle 1、网址&#xff1a;SQL Fiddle - Online SQL Compiler for learning & practiceDiscover our free online SQL editor enhanced with AI to chat, explain, and generate code. Support SQL Server, MySQL, MariaDB, PostgreSQL, and SQLite.http://www.sqlfi…

在Ubuntu-22.04 [WSL2]中配置Docker

文章目录 0. 进入Ubuntu-22.041. 更新系统软件包2. 安装Docker相关依赖包3. 添加Docker官方GPG密钥4. 添加Docker软件源5. 安装Docker Engine5.1 更新软件包列表5.2 安装Docker相关软件包 6. 验证Docker安装是否成功6.1 查看Docker版本信息6.2 启动Docker6.3 配置镜像加速器6.4…

AI大模型ollama结合Open-webui

AI大模型Ollama结合Open-webui 作者:行癫(盗版必究) 一:认识 Ollama 1.什么是Ollama ​ Ollama是一个开源的 LLM(大型语言模型)服务工具,用于简化在本地运行大语言模型,降低使用大语言模型的门槛,使得大模型的开发者、研究人员和爱好者能够在本地环境快速实验、管理和…

使用ensp搭建内外互通,使用路由跨不同vlan通信。

1.网络拓扑图 2.规则 &#xff08;1&#xff09;允许 &#xff08;自己&#xff09;ping通内外网&#xff0c;内外网随便一个pc就可以. &#xff08;2&#xff09; 允许&#xff08;电信&#xff09;ping通内外网&#xff0c;内外网随便一个pc就可以 &#xff08;时间问题不做…

gRPC 快速入门 — SpringBoot 实现(1)

目录 一、什么是 RPC 框架 &#xff1f; 二、什么是 gRPC 框架 &#xff1f; 三、传统 RPC 与 gRPC 对比 四、gRPC 的优势和适用场景 五、gRPC 在分布式系统中应用场景 六、什么是 Protocol Buffers&#xff08;ProtoBuf&#xff09;&#xff1f; 特点 使用场景 简单的…

Python实现BBS论坛自动签到【steamtools论坛】

一、知识点分析 1.requests模块介绍 ‌requests模块是Python中用于发送HTTP请求的一个库,它封装了urllib3库,提供了更加便捷的API接口。‌ 通过使用requests模块,用户可以模拟浏览器的请求,发送HTTP请求到指定的URL,并获取响应内容。与urllib相比,requests模块的API更加…

Probabilistic Face Embeddings 论文阅读

Probabilistic Face Embeddings 论文阅读 Abstract1. Introduction2. Related Work3. Limitations of Deterministic Embeddings4. Probabilistic Face Embeddings4.1. Matching with PFEs4.2. Fusion with PFEs4.3. Learning 5. Experiments5.1. Experiments on Different Bas…

重磅升级:OpenAI o1模型上手实测,从芯片架构分析到象棋残局判断的全能表现

引言 昨日&#xff0c;在圣诞节系列发布会的第一天&#xff0c;OpenAI终于给我们带来了令人振奋的更新&#xff0c;这些更新有望塑造AI互动的未来。备受期待的OpenAI o1正式版的推出&#xff0c;标志着ChatGPT体验的重大进化&#xff0c;宣告了AI驱动应用新时代的开始。o1现已可…

1.使用docker 部署redis Cluster模式 集群3主3从

1.使用docker 部署redis Cluster模式 集群3主3从 1.1 先安装docker 启动docker服务&#xff0c;拉取redis镜像 3主3从我们要在docker启动6个容器docker run --name redis-node-1 --net host --privilegedtrue -v /data/redis/share/redis-node-1:/data redis:6.0.8 --cluster-…

如何通过 Windows 自带的启动管理功能优化电脑启动程序

在日常使用电脑的过程中&#xff0c;您可能注意到开机后某些程序会自动运行。这些程序被称为“自启动”或“启动项”&#xff0c;它们可以在系统启动时自动加载并开始运行&#xff0c;有时甚至在后台默默工作。虽然一些启动项可能是必要的&#xff08;如杀毒软件&#xff09;&a…

记一次跑前端老项目的问题

记一次跑前端老项目的问题 一、前言二、过程1、下载依赖2、启动项目3、打包 一、前言 在一次跑前端老项目的时候&#xff0c;遇到了一些坑&#xff0c;这里记录一下。 二、过程 1、下载依赖 使用 npm install下载很久&#xff0c;然后给我报了个错 core-js2.6.12: core-js…

在米尔FPGA开发板上实现Tiny YOLO V4,助力AIoT应用

学习如何在 MYIR 的 ZU3EG FPGA 开发板上部署 Tiny YOLO v4&#xff0c;对比 FPGA、GPU、CPU 的性能&#xff0c;助力 AIoT 边缘计算应用。 一、 为什么选择 FPGA&#xff1a;应对 7nm 制程与 AI 限制 在全球半导体制程限制和高端 GPU 受限的大环境下&#xff0c;FPGA 成为了中…