【C++】哈希之位图

目录

  • 一、位图概念
  • 二、海量数据面试题

一、位图概念

假如有40亿个无重复且没有排序的无符号整数,给一个无符号整数,如何判断这个整数是否在这40亿个数中?

我们用以前的思路有这些:

  1. 把这40亿个数遍历一遍,直到找到为为止
  2. 排序+二分查找
  3. 位图解决

遍历一遍的时间复杂度为O(N);排序是O(N * logN),二分查找是O(logN),第二种还不如第一种。前面两种方法如果是针对比较小的数据的话,还行。但是如果是数据很大的,效率就低了。所以我们可以使用第三种方法,位图解决查找数据的问题。

位图概念:
位图是通过每一个比特位来判断一个数是否是在还是不在。一个二进制比特位只有两种状态,要么为0,要么为1,如果某个数据在,则对应映射的比特位为1;不在,对应的比特位为0。位图适用于海量数据处理,且数据无重复的场景,时间复杂度为O(1)

在这里插入图片描述

用位图解决前面的问题:

有40亿个无重复且没有排序的无符号整数,给一个无符号整数,如何判断这个整数是否在这40亿个数中?

首先要了解1G大约等于10亿个字节,1个整数等于4个字节,1个字节等于8个比特位。换算下40亿个整数大约是16G。但是我们不可能开出16G的内存去查找一个数,用位图就可以节省很多空间了。一个整数等于32个比特位,根据位图的概念,用每个比特位是1还是0来确定一个数到底在不在,1个整数的32个比特位可以用来确定32个数据的存在,所以16G除以32等于0.5G,即512M,这就是开辟的空间大小,是不是节省多了。

这里是我们自己模拟出来的一个简单的位图,主要有以下接口:

1️⃣构造
使用vector的接口resize开辟出N / 32 + 1的空间大小,每个位置初始化为0,为什么要除32?因为一个整数有32个比特位,这32个比特位存储在vector数组的一个位置里;为什么又要加1?因为假如开的空间大小是50,50/32等于1,那到底是一个位置还是2个位置?很明显是2个,第一个位置刚好满32个比特位,剩余18个比特位也要有位置放,因此要有第二个位置。

2️⃣将该比特位设置为1
每个数都有对应映射的比特位,将这个数除以32找到该数在数组中的位置,取模32找到映射的第几个比特位,1左移前面取模的位数,然后按位或将该比特位设置为1
在这里插入图片描述

3️⃣将该比特位设置为0
前面同上,先按位取反1左移前面取模的位数后的数,然后按位与将该比特位设置为0
在这里插入图片描述

4️⃣判断状态
前面同上,用按位与,映射的位置和1移动后的位都是1才说明这个数在
在这里插入图片描述

类的模板是非类型模板参数,传的是数据的大小。成员变量是vector类型,方便开辟空间。为什么1是左移?注意:左移不是真的往左边移,右移也不是真的往右边移,跟方向没关系。左移是往高位移动,右移是往低位移动;其次,还要看编译器,vs下是小端存储数据的,所以这里是左移。

代码:

namespace yss
{
	template<size_t N>
	class bitset
	{
	public:
		//构造
		bitset()
		{
			_bit.resize(N / 32 + 1, 0);
		}
		//该比特位 置为1
		void set(size_t x)
		{
			size_t i = x / 32;
			size_t j = x % 32;
			_bit[i] |= (1 << j);
		}
		//该比特位 置为0
		void reset(size_t x)
		{
			size_t i = x / 32;
			size_t j = x % 32;
			_bit[i] &= ~(1 << j);
		}
		//该比特位的状态(在/不在)
		bool test(size_t x)
		{
			size_t i = x / 32;
			size_t j = x % 32;
			return _bit[i] & (1 << j);
		}

	private:
		vector<int> _bit;
	};
}

void Func1()
{
	yss::bitset<100> bs;
	bs.set(30);
	bs.set(60);
	bs.set(90);
	for (size_t i = 0; i < 100; i++)
	{
		if (bs.test(i))
		{
			cout << i << "->" << "在" << endl;
		}
		else
		{
			cout << i << "->" << "不在" << endl;
		}
	}
}

40亿个数据,如下:

yss::bitset<-1>* bs = new bitset<-1>;//第一种写法
yss::bitset<4294967295>* bs = new bitset<4294967295>;//第二种写法

栈的空间有限,对于很大的数据,需要大量的内存空间,应该通过堆来申请。其他同上面代码。

二、海量数据面试题

1️⃣给定100亿个整数,设计算法找到只出现一次的整数?

思路:

  • 使用两个位图来实现,表示00(没有出现) - 01(出现一次) - 10 - 11 的情况(后面两个是出现2个及2个以上),本题是找到只出现一次的整数,所以最终判断这个整数在不在的条件是两个位图映射的比特位是不是01
  • 有100亿个整数,为了映射所有整数,一个位图开辟的空间大小是512M,即2的32次方个比特位,两个合起来是占1G内存

代码:

int main()
{
	vector<int> a{ 2,2,3,3,5,8,8,14,14,66 };
	bitset<-1>* bs1 = new bitset<-1>;//指针
	bitset<-1>* bs2 = new bitset<-1>;
	
	for (auto e : a)
	{
		if (bs1->test(e) == false && bs2->test(e) == false)
		{
			bs2->set(e);//00->01
		}
		else if (bs1->test(e) == false && bs2->test(e) == true)
		{
			bs1->set(e);
			bs2->reset(e);//01->10
		}
		else
		{
			//
		}
	}
	for (size_t i = 0; i < -1; i++)
	{
		if (bs1->test(i) == false && bs2->test(i) == true)
		{
			cout << i << endl;// 5   66
		}
	}
	return 0;
}

2️⃣给两个文件,分别有100亿个整数,我们只有1G内存,如何找到两个文件交集?

思路:

  • 既然给两个文件,那么也要用两个位图。100亿个整数,跟前面一样,一个位图也是512M,两个位图刚好1G
  • 只需判断某个数据在两个位图是否存在即可,如果两个位图的对应映射的比特位都是1,就是交集;反之,有一个不是1,或者两个都是0就不是交集

代码:

int main()
{
	vector<int> a1{ 2,4,6,8,10,14,20 };
	vector<int> a2{ 1,3,4,5,7,9,10,17 };
	bitset<-1>* bs1 = new bitset<-1>;
	bitset<-1>* bs2 = new bitset<-1>;
	for (auto e : a1)
	{
		bs1->set(e);
	}
	for (auto e : a2)
	{
		bs2->set(e);
	}
	for (size_t i = 0; i < -1; i++)
	{
		if (bs1->test(i) == true && bs2->test(i) == true)
		{
			cout << i << endl;// 4  10
		}
	}
	return 0;
}

3️⃣1个文件有100亿个int,1G内存,设计算法找到出现次数不超过2次的所有整数

思路:

  • 步骤同问题1,在它的基础上增加了10->11的情况,即出现3次和3次以上,然后最后判断条件为出现1次和2次的数据打印出来

代码:

int main()
{
	vector<int> a{ 2,4,4,5,5,5,7,9,9,9,9 };
	bitset<-1>* bs1 = new bitset<-1>;
	bitset<-1>* bs2 = new bitset<-1>;
	for (auto e : a)
	{
		if (bs1->test(e) == false && bs2->test(e) == false)
		{
			bs2->set(e);//00->01 出现1次
		}
		else if (bs1->test(e) == false && bs2->test(e) == true)
		{
			bs1->set(e);
			bs2->reset(e);//01->10 出现2次
		}
		else if (bs1->test(e) == true && bs2->test(e) == false)
		{
			bs2->set(e);//10->11 出现3次
		}
		//3次以上
	}
	for (size_t i = 0; i < -1; i++)
	{
		if ( (bs1->test(i) == false && bs2->test(i) == true)
			|| (bs1->test(i) == true && bs2->test(i) == false))
		{
			cout << i << endl;// 2  4  7
		}
	}
	return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

鸿蒙OS元服务开发:【(Stage模型)设置悬浮窗】

一、设置悬浮窗说明 悬浮窗可以在已有的任务基础上&#xff0c;创建一个始终在前台显示的窗口。即使创建悬浮窗的任务退至后台&#xff0c;悬浮窗仍然可以在前台显示。通常悬浮窗位于所有应用窗口之上&#xff1b;开发者可以创建悬浮窗&#xff0c;并对悬浮窗进行属性设置等操…

frp内网穿透之(反向代理nginx)

通过公网 https 连接访问内网&#xff08;局域网&#xff09;本地http服务如下&#xff1a; 1.准备工作 ​ 想要实现内网穿透功能首先我们需要准备&#xff1a; 一台公网服务器&#xff08;用作frps的服务端&#xff09;一台需要做转发的内网服务器&#xff08;用作frpc的客…

D-迷恋网游(遇到过的题,做个笔记)

我的代码&#xff1a; #include <iostream> using namespace std; int main() {int a, b, c; //a表示内向&#xff0c;b表示外向&#xff0c;c表示无所谓cin >> a >> b >> c; //读入数 if (b % 3 0 || 3-b % 3 < c) //如果外向的人能够3人组成…

Golang Channel底层实现原理

1、本文讨论Channel的底层实现原理 首先&#xff0c;我们看Channel的结构体 简要介绍管道结构体中&#xff0c;几个关键字段 在Golang中&#xff0c;管道是分为有缓冲区的管道和无缓冲区的管道。 这里简单提一下&#xff0c;缓冲区大小为1的管道和无缓冲区的管道的区别&…

Android14之BpBinder构造函数Handle拆解(二百零四)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

详解人工智能(概念、发展、机遇与挑战)

前言 人工智能&#xff08;Artificial Intelligence&#xff0c;简称AI&#xff09;是一门新兴的技术科学&#xff0c;是指通过模拟、延伸和扩展人类智能的理论、方法、技术和应用系统&#xff0c;以实现对人类认知、决策、规划、学习、交流、创造等智能行为的模拟、延伸和扩展…

Linux 线程互斥、互斥量、可重入与线程安全

目录 一、线程互斥 1、回顾相关概念 2、抢票场景分析代码 多个线程同时操作全局变量 产生原因 如何解决 二、互斥量 1、概念 2、初始化互斥量&#xff1a; 方法1&#xff1a;静态分配 方法2&#xff1a;动态分配 3、销毁互斥量&#xff1a; 4、加锁和解锁 示例抢…

MySQL 8.0.13安装配置教程

写个博客记录一下&#xff0c;省得下次换设备换系统还要到处翻教程&#xff0c;直接匹配自己常用的8.0.13版本 1.MySQL包解压到某个路径 2.将bin的路径加到系统环境变量Path下 3.在安装根目录下新建my.ini配置文件&#xff0c;并用编辑器写入如下数据 [mysqld] [client] port…

基于jsp网上教师点评系统

基于jsp网上教师点评系统 关键词&#xff1a;教师点评 信息技术 JSP技术 系统实现 首页 评分规则 教室信息 后台首页 相关技术介绍 B/S架构 对于架构&#xff0c;听起来说我们可能比较陌生&#xff0c;但对于通俗的语法讲。他的访问方式是通过网址还是说通过点图标这…

YoloV8改进策略:Neck改进|GCNet(独家原创)|附结构图

摘要 本文使用GCNet注意力改进YoloV8,在YoloV8的Neck中加入GCNet实现涨点。改进方法简单易用&#xff0c;欢迎大家使用&#xff01; 论文:《GCNet: Non-local Networks Meet Squeeze-Excitation Networks and Beyond》 非局部网络&#xff08;NLNet&#xff09;通过为每个查…

Flex布局:打造灵动、响应式网页设计的利器

Flex布局&#xff08;Flexible Box Layout&#xff09;&#xff0c;也称为弹性盒布局&#xff0c;是一种现代CSS布局模式&#xff0c;旨在为复杂、响应式的网页设计提供更加灵活、简洁的解决方案。Flex布局通过定义一个弹性容器&#xff08;flex container&#xff09;及其内部…

49岁前港姐退圈出嫁「南丫岛王子」,打排卵针高龄连生两女。

现年49岁的吴忻熹&#xff08;原名吴文忻&#xff09;1998年参选香港小姐夺得季军入行&#xff0c;在TVB签约发展平平&#xff0c;继而转战影坛&#xff0c;凭性感演出而为人熟悉。其后她在2011年嫁给有「南丫岛王子」之称的金融才俊&#xff0c;并在近40岁开始诞下两名女儿。吴…

Set a Light 3D Studio:探索光影艺术的全新维度mac/win中文版

Set a Light 3D Studio 是一款领先的三维建模和渲染软件&#xff0c;它将设计师、艺术家和摄影师的创意想法转化为生动逼真的三维场景。这款软件以其强大的功能和直观的界面&#xff0c;成为行业内众多专业人士的首 选工具。 set.a.light 3D STUDIO中文版软件获取 在Set a Lig…

最简单的 AAC 音频码流解析程序

最简单的 AAC 音频码流解析程序 最简单的 AAC 音频码流解析程序原理源程序运行结果下载链接参考 最简单的 AAC 音频码流解析程序 参考雷霄骅博士的文章&#xff1a;视音频数据处理入门&#xff1a;AAC音频码流解析 本文中的程序是一个AAC码流解析程序。该程序可以从AAC码流中…

信息系统项目管理师——第17章项目干系人管理

本章节内容属于10大管理知识领域&#xff0c;选择、案例、论文都会考。 选择题&#xff0c;稳定考1-2分左右&#xff0c;新教材基本考课本原话&#xff0c;这个分不能丢。 案例题&#xff0c;本期考的概率一般。 论文题&#xff0c;202205期考过。 1管理基础 管理的重要性 为…

QT5-qmediaplayer播放视频及进度条控制实例

qmediaplayer是QT5的播放视频的一个模块。它在很多时候还是要基于第三方的解码器。这里以Ubuntu系统为例&#xff0c;记录其用法及进度条qslider的控制。 首先&#xff0c;制作一个简单的界面文件mainwindow.ui&#xff1a; 然后&#xff0c;下载一个mp4或其他格式视频&#x…

爬虫 红网时刻 获取当月指定关键词新闻 并存储到CSV文件

目标网站&#xff1a;红网 爬取目的&#xff1a;为了获取某一地区更全面的在红网已发布的宣传新闻稿&#xff0c;同时也让自己的工作更便捷 环境&#xff1a;Pycharm2021&#xff0c;Python3.10&#xff0c; 安装的包&#xff1a;requests&#xff0c;csv&#xff0c;bs4&…

计算多个元素的累乘结果累乘器start默认初始为1 math.prod()

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 计算多个元素的累乘结果 累乘器start默认初始为1 math.prod() [太阳]选择题 请问题目中的代码最后输出什么? import math list1 [1, 2, 3] print("【显示】list1 ",list1) pri…

如何将本地仓库放到远程仓库中

在我们仓库创建好之后&#xff0c;我们复制好ssh 接着我们需要使用git remote add<shortname><url>这个命令 shortname就是我们远程仓库的别名 接着使用git remote -v这个命令查看一下目前远程仓库的别名和地址 原本还有一个指令git branch -M main 指定分支的名…

智能试卷分析、智能组卷系统

本课题开发一个新型智能试卷分析评价系统&#xff0c;该系统实现了学生试卷的生成与评估以及对各种评估信息的管理和维护。该系统使用SpringBoot MysqlVue搭建的框架为设计平台&#xff0c;以B/S模式开发与设计题库及试卷管理模块。 学生功能&#xff1a;登录&#xff0c;答题考…