C++实现位图

目录

一、什么是位图

二、位图类

1.参数及构造函数

2.set函数设置为1(代表存在) 

3.reset函数设置为0(代表不存在)

4.test函数查看状态(0还是1)

三、位图的变形


一、什么是位图

位图这个词汇比较少见,在学习位图之前,我们可以先来看看下面这个问题

40亿个数,大约为2^32。 这里有几个方案解决

解决方案1:暴力查找,将数据遍历一遍直到找到,但是40亿个数据太大了,如果换算为整数,那么至少需要16G(4*2^32代表4个字节,再乘以个数)的内存,一般的电脑是没办法开辟出这么大的连续空间的。

解决方案2:就是已经是有序了我们只需二分查找,二分查找的效率为log(n),但这里跟效率没啥关系,主要还是无法开辟这么大的内存的问题

解决方案3:将数据放到unordered_set或者set中,使用哈希表和红黑树的思想帮我们查找,但是哈希表和红黑树他们存放的结点会占用更多的空间,因为存放的结点不仅仅有数据,还有指针,因此更无法使用。

前面的几个解决方案都没有办法解决这种较大数据的问题,那么我们引入概念位图。

每一个值映射一个bit位,那么我们只需要一个bit位就可以知道该位置的值是否存在了,0为不存在,1为存在。这就叫做位图。

那么40亿个数据按照这种方法来表示他们是否存在的状态,只需要0.5G(2^32/8 代表所有的数据除以每个字节的8位)

二、位图类

其实库里面也有bitset位图,我们模仿一下这个位图的基本函数。

1.参数及构造函数

我们写出一个类,类的模板参数只有一个常量,代表我们要存放多少个数据的状态(bit位),类成员为vector<int> _bits; 

同时构造参数是给_bits开辟足够的空间,_bits.resize(N / 32 + 1, 0);   N/32代表一个整形的每一个bit位都存放状态,+1是为了防止除数把余数丢掉,比如40/32==1,如果我们只开辟一个int整形,就会将后面的数据丢掉。

template<size_t N>
class bitset
{
public:bitset(){_bits.resize(N / 32 + 1, 0);}
private:vector<int> _bits;
}

2.set函数设置为1(代表存在) 

 有了这个,我们如何来设置,让我们想要映射的位置变为1呢?

首先,参数部分肯定需要一个整数,代表是这个数据,我们可以通过 x/32 来表示映射到哪一个整形里了,再通过 x%32来表示映射该整形的哪一个bit位。这样我们就可以找到映射的位置了,找到位置后,应该如何将他的值赋为1呢?

我们的想法是让他无论是为0还是为1,我都要设置为1,这样初步会考虑到 |(或运算),肯定是 | 上1,我们可以通过左移运算符,将1左移到想要的位置,也就是 j 位置。这样进行或运算,就可以保证在不影响其他位置的值的前提,将想要的位置置为1了

代码如下 

void set(size_t x)
{int i = x / 32;int j = x % 32;_bits[i] |= (1 << j);
}

3.reset函数设置为0(代表不存在)

有了设置存在,我们也得设置不存在,如何操作呢?

一样的方法先找到 i 和 j ,无论该值为1还是为0,要想设置为0,就需要&(与运算)0才行那我们将 1 左移 j 位,再取反,就让想要的bit位变成了0,其他位都为1。

任何数(指0和1)与上1都是他本身,这样就没有改变其他bit位,任何数与上0都为0,这样就达到我们的设置改bit位为 0 目的了。

代码如下 

void reset(size_t x)
{int i = x / 32;int j = x % 32;_bits[i] &= ~(1 << j);
}

4.test函数查看状态(0还是1)

 有了置为1和置为0,我们还需要去查看该位置的状态。

依然是计算出  i  和  j  ,与上(1<<j)返回即可,因为任何数(指0和1)与上1都是他本身,因此我们状态为0就返回0,为1就返回1,就知道该位置的状态了。

bool test(size_t x)
{int i = x / 32;int j = x % 32;return _bits[i] & (1 << j);
}

测试一下,没有问题,这样就极大的节省了空间。

三、位图的变形

 如下面这个题,就是位图的变形题。

 这里也有两个方案去解决。

方案1:将单位图修改为双位图,从整形存放32个状态(0或1),编程存放16个(00或01或10)状态。由于找到只出现一次的整数,那么状态我们只需要设置(00或01或10)分别代表0个、1个、2个及以上。这个方案虽然可行,但是要重新修改位图,比较麻烦。

方案2:再写一个类,变量为两个位图,第一个位图代表状态(00或01或10)的前一个bit位,第二个位图代表状态(00或01或10)的后一个bit位

很明显,代码复用要香很多,我们选择方案2。

 set函数中,如果bit1的test(x)为false,bit2的test(x)也为false,那么就将bit2的该位置设置为1。

如果bit1的test(x)为false,bit2的test(x)为true,就将bit1位置设置为1,bit2位置设置为0,就完成了。

再写一个打印函数就完成了。

具体代码如下

template<size_t N>
class twobitset
{
public:void set(size_t x){if (bit1.test(x) == false && bit2.test(x) == false){bit2.set(x);}else if (bit1.test(x) == false && bit2.test(x) == true){bit1.set(x);bit2.reset(x);}}void PrintOnce(){for (size_t i = 0; i < N; i++){if (bit1.test(i) == false && bit2.test(i) == true){cout << i << endl;}}cout << endl;}
private:bitset<N> bit1;bitset<N> bit2;
};

代码测试,没问题。

该位图只涉及到了整数的处理,如果是字符串怎么处理呢?需要用到布隆过滤器,这个我们下次再讲。

最后附上总代码

bitset.h

#pragma once
#include<vector>
namespace kky
{template<size_t N>class bitset{public:bitset(){_bits.resize(N / 32 + 1, 0);}void set(size_t x){int i = x / 32;int j = x % 32;_bits[i] |= (1 << j);}void reset(size_t x){int i = x / 32;int j = x % 32;_bits[i] &= ~(1 << j);}bool test(size_t x){int i = x / 32;int j = x % 32;return _bits[i] & (1 << j);}private:vector<int> _bits;};template<size_t N>class twobitset{public:void set(size_t x){if (bit1.test(x) == false && bit2.test(x) == false){bit2.set(x);}else if (bit1.test(x) == false && bit2.test(x) == true){bit1.set(x);bit2.reset(x);}}void PrintOnce(){for (size_t i = 0; i < N; i++){if (bit1.test(i) == false && bit2.test(i) == true){cout << i << endl;}}cout << endl;}private:bitset<N> bit1;bitset<N> bit2;};
}

 test.cpp

#include<iostream>
using namespace std;
#include"bitset.h"
//int main()
//{
//	kky::bitset<100> bs;
//	bs.set(10);
//	bs.set(11);
//	
//	cout << bs.test(9) << endl;
//	cout << bs.test(10) << endl;
//	cout << bs.test(11) << endl;
//	cout << bs.test(12) << endl;
//	bs.reset(10);
//	cout << bs.test(10) << endl;
//}int main()
{int a[] = { 1,3,4,6,8,4,6,3,1,5,7 };kky::twobitset<100> bs;for (auto e : a){bs.set(e);}bs.PrintOnce();
}

谢谢大家观看!!! 

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

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

相关文章

【高效开发工具系列】eclipse部署web项目

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

【数字图像处理】实验一 图像基本运算

图像基本运算 一、实验内容&#xff1a; 1&#xff0e; 熟悉和掌握利用Matlab工具进行数字图像的读、写、显示等数字图像处理基本步骤。 2&#xff0e; 熟练掌握各种图像点运算的基本原理及方法。 3&#xff0e; 能够从深刻理解点运算&#xff0c;并能够思考拓展到一定的应用领…

智能优化算法应用:基于堆优化算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于堆优化算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于堆优化算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.堆优化算法4.实验参数设定5.算法结果6.参考文…

【论文笔记】3D Gaussian Splatting for Real-Time Radiance Field Rendering

原文链接&#xff1a;https://arxiv.org/abs/2308.04079 1. 引言 网孔和点是最常见的3D场景表达&#xff0c;因其是显式的且适合基于GPU/CUDA的快速栅格化。神经辐射场&#xff08;NeRF&#xff09;则建立连续的场景表达便于优化&#xff0c;但渲染时的随机采样耗时且引入噪声…

显示器屏幕oled的性能、使用场景、维护

OLED显示器屏幕具有许多独特的性能和使用场景&#xff0c;以下是关于OLED显示器屏幕的性能、使用场景和维护的详细介绍&#xff1a; 一、性能 色彩鲜艳&#xff1a;OLED显示器屏幕能够呈现出更加鲜艳的色彩&#xff0c;色彩饱和度高&#xff0c;色彩还原性好&#xff0c;可以给…

美好蕴育润康:为孕产期女性量身定制的专业营养

如今&#xff0c;孕产期是女性人生中特别而又重要的阶段。这段时间&#xff0c;孕期妈妈经常饱受许多痛苦和不适&#xff0c;更需要额外的关爱和呵护&#xff0c;以确保母婴健康。为了满足孕产期女性特殊的营养需求&#xff0c;美好蕴育润康应运而生&#xff0c;成为她们身边的…

关于“Python”的核心知识点整理大全35

目录 13.3.4 重构 create_fleet() game_functions.py 13.3.5 添加行 game_functions.py alien_invasion.py 13.4 让外星人群移动 13.4.1 向右移动外星人 settings.py alien.py alien_invasion.py game_functions.py 13.4.2 创建表示外星人移动方向的设置 13.4.3 检…

在Portainer创建Nginx容器并部署Web静态站点实现公网访问

&#x1f525;博客主页&#xff1a; 小羊失眠啦. &#x1f3a5;系列专栏&#xff1a;《C语言》 《数据结构》 《Linux》《Cpolar》 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;…

uniapp如何原生app-云打包

首先第一步&#xff0c;需要大家在HBuilder X中找到一个项目&#xff0c;然后呢在找到上面的发行选项 发行->原生App-云打包 选择完该选中的直接大包就ok。 大包完毕后呢&#xff0c;会出现一个apk包&#xff0c;这是后将这个包拖动发给随便一个人就行了。 然后接收到的那…

二分查找法详解(6种变形)

前言 在之前的博客中&#xff0c;我给大家介绍了最基础的二分查找法&#xff08;没学的话点我点我&#xff01;&#xff09; 今天我将带大家学习二分法的六种变形如何使用&#xff0c;小伙伴们&#xff0c;快来开始今天的学习吧&#xff01; 文章目录 1&#xff0c;查找第一个…

浏览器的工作原理 - 从输入URL 按下回车到页面展示过程发生了什么?

本文带大家一起了解一下从我们输入一个网址链接开始到页面展示在我们面前&#xff0c;整个浏览器发生了什么&#xff1f;或者说浏览器做了哪些事&#xff0c;咱们以大家常用的baidu.com为例&#xff0c;从输入到 baidu.com 页面出现的整个流程 第一步&#xff1a;地址栏中敲击第…

基于ssm家具销售库存管理信息系统的设计与实现论文

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本家具销售库存管理信息系统就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理完毕庞大的…