当前位置: 首页 > article >正文

哈希的应用——位图

目录

一,引入

二,问题引入

三,std里的位图

四,位图的实现

1.成员

2.初始化

3.set成员函数(如果一个数出现便将对应的比特位改为1)

4.reset函数(如果一个数出现便将对应的比特位改为0)

5.test函数(检验数字存不存在)

5.检验

详细代码:


一,引入

首先介绍一下位图,位图是啥呢?所谓位图,就是用每一位来存放某种状态,适用于海量数据,数据无重复的场景。通常是用 来判断某个数据存不存在的。首先在这里解释一下:

1.位图的位是比特位。

2.位图面对的海量数据是整形的海量数据。

所以这里便暴露了位图的一个局限性,位图只能用来查找整形数据。

二,问题引入

第一道题是一道面试题,题目如下:

1. 面试题

40 亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在
40 亿个数中。【腾讯】
  这道题便是要使用位图来解决的一道经典题目。首先40亿个数字绝对算得上是海量数据,其次我们要查找的是整数。使用位图的两个条件都有了,所以这道题可以使用位图。
  那我们为什么不使用其它的数据结构来解决这道题呢?比如红黑树,哈希表,AVL树这些高效率的数据结构?其实主要在一个点: 海量数据光是存储都能把内存折腾光了。所以使用这些数据结构是万万不能的。所以我们只能用位图了。

三,std里的位图

传送门:std里的bitset

在手撕位图之前,先来把std库里的位图的样子看一遍,如下图:

    首先我们可以知道位图叫:bitset,其次位图是一个非类型参数的模板类(参数的类型已确定是一个size_t类型)。

    其次我们再来看看这个N是啥意思:

通过这个解释我们知道了,N是number of bits。所以N就代表比特位的数量。好了现在我们把位图的大概样子摸清楚了,现在就来实现一下吧。

四,位图的实现

1.成员

在实现这个位图时,为了简单一点。我的成员就直接采用vector<int>了。定义如下:

template<size_t N>//非类型模板参数

class bitset
{
     
 private:
	vector<char>bits;
};

2.初始化

   一个类要初始化,我们使用的肯定是构造函数。但是要开多少个比特位,表示的数的范围是多少这些都是要我们传进去的。所以我们在初始化时一定要使用带有参数的构造函数,并且这个参数就是我们的N(N是非类型模板参数) 。在初始化时便可以复用vector里面的resize()函数,但是resize()函数里面传的个数代表的整型的个数,而我们要的个数确是比特位的个数所以在这里便要处理一下:N/32+1(表示要开的整型的个数)代码如下:

bitset()
{
   bits.resize(N /32 + 1,0);//开空间,开的是整型值的空间,并且要初始化为0
}

3.set成员函数(如果一个数出现便将对应的比特位改为1)

   首先我们要明确的是每一个比特位对应着一个数。那我们的映射关系该如何处理呢?

其实也简单,要分两步:

1.找到你所在的整数下标,int i = x/32。

2.找到你在这个整数的第几个比特位,int j = x%32。

比如我开了100个比特位。那我对应的整数的个数便是n = 100/32+1,一共有4个整数0。

那如果我插入一个40,40映射的位置是多少呢?

1.整数下标:i = 40/32 ==1。

2.所在比特位:j = 40%32 == 8。

    然后我们要做的便是将40映射的位置的值改为1,其它位置不变。如何搞呢?其实也简单,就是将所在的整数或等(|=)(i<<j)。如下代码所示:

void set(size_t x)//把对应整数的比特位置为1
{
	int i = x / 32;//表示在第几个整数。i表示下标
	int j = x % 32;//对应的整数的比特位。

	bits[i] |= (1 << j);
}

4.reset函数(如果一个数出现便将对应的比特位改为0)

在写完set函数 以后,我们已经知道了如何找到映射的比特位了。所以在这里要做的便是将映射的比特位上的数字改为0,其它位置不变。如何操作呢,其实也简单。如下:

void reset(size_t x)//把对应整数的比特位置为0
{
   int i = x / 32;//表示在第几个整数。i表示下标
   int j = x % 32;//对应的整数的比特位。

   bits[i] &= ~(1 << j);
}

5.test函数(检验数字存不存在)

 如何检验一个数字存不存在呢?还是一样,先找到这个数字的映射比特位。然后让这再让这个数字映射的比特位所在的整数做&(1<<j)的操作。如在就得到一个非零数,如不在便得到一个0。代码如下:

bool test(size_t x)//检查是否出现
{
  int i = x / 32;//表示在第几个整数。i表示下标
  int j = x % 32;//对应的整数的比特位。

  return bits[i] & (1 << j);
}

5.检验

现在我们得想一想了,我们要开多大的数据呢?多少个比特位呢?是40亿个比特位吗?

1.首先我们要明确:不是40亿个比特位。而是42亿九千万....个比特位(无符号整型的最大值个)。

2.那我们该如何开呢?用INT_MAX行吗?不行因为INT_MAX是有符号整型的最大值。那2*INT_MAX呢?还是不行,因为溢出然后被截断。

3.我们应该使用的是-1或者0xffffffff,来开空间。因为我们在类里面使用到的是size_t类型的参数,传入-1会被识别为最大的无符号整型值。

验证如下:

详细代码:

template<size_t N>//非类型模板参数

	class bitset
	{
	public:
		bitset()
		{
			bits.resize(N /32 + 1,0);//开空间,开的是整型值的空间,并且要初始化为0
		}

		void set(size_t x)//把对应整数的比特位置为1
		{
			int i = x / 32;//表示在第几个整数。i表示下标
			int j = x % 32;//对应的整数的比特位。

			bits[i] |= (1 << j);
		}

		void reset(size_t x)//把对应整数的比特位置为0
		{
			int i = x / 32;//表示在第几个整数。i表示下标
			int j = x % 32;//对应的整数的比特位。

			bits[i] &= ~(1 << j);
		}

		bool test(size_t x)//检查是否出现
		{
			int i = x / 32;//表示在第几个整数。i表示下标
			int j = x % 32;//对应的整数的比特位。

			return bits[i] & (1 << j);
		}

	private:
		vector<char>bits;
	};


http://www.kler.cn/news/137218.html

相关文章:

  • 用.NET开发跨平台应用程序采用 Avalonia 与MAUI如何选择
  • Unity--AssestBundles--热更新
  • 排序02 Multi-gate Mixture-of-Experts (MMoE)
  • 图片写入GPS经纬高信息
  • ros中私有参数
  • AlDente Pro for Mac电脑 充电限制保护工具 安装教程【简单,轻松上手】
  • 【shell脚本】全自动完成pxe无人值守批量装机脚本,匹配centos系列
  • Unity中Shader法线贴图(下)实现篇
  • 拉链表-spark版本
  • Python等于号标红怎么办,可能原因
  • React 自定义hook 之 防抖和节流
  • 很多人都在用的现货白银突破交易法 缺点需要注意
  • Qt Widget 自定义TitleBar带阴影窗口
  • 3PC(三阶段提交)
  • redis运维(七)基础通用命令
  • Flutter笔记:使用相机
  • 数字IC前端学习笔记:时钟切换电路
  • Idea2023 Springboot web项目正常启动,页面展示404解决办法
  • 论文《A recurrent latent variable model for sequential data》笔记:详解VRNN
  • 京东商品详情数据接口【京东API接口开发系列】,监控京东价格走势,接口代码示例,可高并发批量获取
  • 二百零四、Flume——登录监听窗口报错Ncat: bind to :::44444: Address already in use. QUITTING.
  • 005 OpenCV直方图
  • 【Spring】SpringBoot的扩展点之ApplicationContextInitializer
  • INFINI Labs 产品更新 | 发布 Easysearch Java 客户端,Console 支持 SQL 查询等功能
  • 基于java的学生考勤信息管理系统设计【附源码】
  • 面向未来的自动化:拥抱机器人即服务(RaaS)