Learning C++ No.26 【深入学习位图】

这篇具有很好参考价值的文章主要介绍了Learning C++ No.26 【深入学习位图】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

引言:

北京时间:2023/5/30/15:30,刚睡醒,两点的闹钟,硬是睡到了2点40,那种睡不醒的感觉,真的很难受,但是没办法,欠的课越来越多,压的我喘不过气了都,早上把有关unordered_set和unordered_map的内容给写完了,所以哈希表有关代码方面的知识,我们就搞定的差不多了,并且现在外面高温异常,着实比较恐怖,下午四点还要去进行一场有关计算机导论的考试,目前丝毫没有复习,但我也丝毫不慌张,导论这种课现在给我的感觉,就有点像是……具体不好比喻,反正给我的感觉不怎么好,也许以后等我学习的更加深入时,对于这种课程的感觉就会更加清晰吧!并且还是那句话,60分就好,所以咱不慌,哈哈哈!所以今天我们就接着哈希表相关知识,来看看什么是位图结构,虽然之前学习文件操作时学习过,但只是浅浅的了解了一下,这次我们是深入学习位图结构哦!
Learning C++ No.26 【深入学习位图】

图是什么

图给我的第一印象

自从我们接触数据结构开始,我们就知道数据结构中有线性结构、非线性结构,并且知道在学习完线性结构相关的容器之后,就有两座大山,也就是有关树状结构和图状结构,当时在还没有学习什么红黑树、AVL树等容器时,树状结构和图在我的感知中都是较为复杂的数据结构,并且因为图在树之后学习,让我认为图比树的学习难度还更大,所以这就是图给我带来的第一印象,今天我们就来看看图,到底有没有想象中的那么复杂

到底什么是图

经过我的一番学习之后,我意识到了,在数据结构中图并不是我们生过中理解的地图或者纸图,而是位图,那么什么是位图呢?
简简单单,想要快速认识位图,我们从一个经典的面试题目进行分析,如下:

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

首先,看到这种有关查找某个元素的问题,不就是去调用查找接口就可以搞定吗?那么像vector、list这些容器不都有查找接口吗?此时只需要将对应的数据插入到该容器中,然后不就可以调用该容器对应的查找接口去查找该元素是否存在于这些数据之中了吗?当然有的同学会认为,这样的查找方式效率非常的低,可以改进,将数据进行排序,排完序之后,使用二分查找法,在O(logN)的时间复杂就可以轻轻松松搞定,又快又好,或者是使用查找效率更高的数据结构,如红黑树或哈希表,这样就可以将查找效率大大提高啦!这个问题不是很简单吗?但是此时由于数据量是40亿的原因,所以上述方法并不适用,主要涉及到了存储相关的知识,数据量大越大,存储就越困难,并且明白,我们电脑的内存一般是4G~16G,并且这其中还包括了操作系统等软硬件使用的那部分,所以真正能够提供给我们使用的内存大约只有12G到15G,然而,此时如果是40亿个整形数据的话,单单是这方面的数据就需要16G的内存,还没有包括像红黑树中每个结点需要有一个指针,否则就又需要16G,哈希表同理,有而外指针需要存储,所以使用哈希表和红黑树来处理这个问题非常的不明智

充分认识位图

所以想要解决这个问题,那么此时最好的方法就是使用位图结构,原因就是,位图是一种用比特位来表示数据集合的数据结构,它将一个整数集合视为一个由0或1组成的二进制序列,并使用其中每一个比特位来代表对应被存储的整形数据 ,表示的意思就是我们可以使用比特位来标示每一个整形数据,例:此时某一个整数集合{1,2,3,4,5},某一个位图结构00000000,如果对应的整数集合中存在1,我们就把位图结构中的某个比特位由0置1,00000001,如果存在2,那么同理将位图结构中的某个比特位由0置成1,00000011,以此类推,最终把整数集合中的所有数据通过比特位的形式标示出来,这样我们就极大的节省了空间,假如还是40亿个整形数据,那么就不需要16G内存=160亿字节=1280亿个比特位,而只需要40亿个比特位=5亿字节=0.5G内存就可以将40亿个整形数据存储到内存啦!

位图结构代码实现

所以上述就是有关位图结构的基本认识,也就是今天我们学习的重点,文字描述起来,比较抽象,如果对于新手来收,那么想要理解,还是有一定成本的,所以为了更好的认识位图结构,此时我们就来看看如何使用代码来实现位图结构吧!如下:

1.位图基本模型
Learning C++ No.26 【深入学习位图】
2.位图结构代码实现
根据上述的基本模型,此时我们对位图结构就有了更深一步的认识,此时我们再通过代码实现,将该结构给搞定吧!当然我们只是简单实现位图中最关键的接口,如下:

将对应位置由0置1
Learning C++ No.26 【深入学习位图】
将对应位置由1置0
Learning C++ No.26 【深入学习位图】
判断该数据是否存在
当然也就是判断该数据对应的比特位是1还是0,判断方法如下图所示:
Learning C++ No.26 【深入学习位图】

位图结构有关变形问题

1.在100亿个数据中找只出现一次的数据

本质还是在利用上述位图结构有关的知识,只不过此时使用的是两个位图结构,其中一个位图结构用于记录第一次出现的数据,另一个位图结构用于记录第二次出现的数据,具体代码如下图所示:
Learning C++ No.26 【深入学习位图】

2.两个有100亿整数的文件,只有1G内存,如何找到两个文件的交集

最优思路读取文件1的数据映射到位图1,读取文件2的数据映射到位图2,如果两个位置都是1就说明是交集,反之不是交集(注意:每个位图的位置代表的都是不同的值)

总结:位图有关知识就是用来解决类似上述这种海量数据处理问题,使用位图结构就是在使用最少的空间,去存储最多的数据

上述完整代码如下:文章来源地址https://www.toymoban.com/news/detail-466697.html

#pragma once
//明白计算机的移位,无论如何都是1左移几位,然后到达第几位 00000001左移几位得到0000x000
//左移和右移的本质一定是低位到高位(左移)或者高位到低位(右移)

#include<iostream>
#include<vector>

using namespace std;

//1.40亿个数据中,找某一个数据

template<size_t N>//这样子的模板参数需要注意
class bitmap
{
public:
	bitmap()
	{
		_bits.resize(N / 8 + 1, 0);//这样子去开比特位会导致取整时比特位丢失(并且注意:此时N代表的是N个比特位,所以此时resize代表的是开辟多少个字节) 
	}

	void set(size_t x)//将对应的比特位置成0
	{
		size_t i = x / 8;
		size_t j = x % 8;
		//找到对应的位之后,此时就需要将对应的位置成1
		_bits[i] |= (1 << j);//这个不敢看不同,就是数组下标1处的char(8个比特位)去按位或上1左移j为后的二进制,如果j为4,那么也就是按位或上00010000(注意:是从右边开始)
		//也就是 00000000按位或上00010000 最终得到 00010000(并且注意此时是按位或等)

	}

	void reset(size_t x)//将对应的比特位置成1
	{                                                    //     0       1        2        3
		//1.先算是在第几个8比特位(也就是第几个第几个char) 00000000 00000000 00000000 00000000  (注意:需要从右开始计算比特位,因为此时是char类型)
		size_t i = x / 8;//也就是计算x映射的位,在数组位置中的第几个char,如果x为12,那么此时该x的位就在第一个数组下标中
		size_t j = x % 8;//也就是计算x映射的位,在该数组下标char中的第几个位,同理x为12,那么此时x就位于char中的第4个位
		//所以总的来说,此时该x的位置就是第二个char(也就是数组下标为1)中的第四个位
		//所以代码来到这里,就表示我们已经找到对应的位置了
		
		//明白一个点,0跟任何数按位或还是任何数,0跟任意数按位与还是0
		//所以此时我们想要将对应的比特位置0,此时使用的就是按位与(让对应为1的位置和0进行按位与)
		_bits[i] &= ~(1 << j);//同理,00010000按位与上~(00010000)=>11101111,最终得到00000000
	}

	bool test(size_t x)//判断在不在
	{
		size_t i = x / 8;
		size_t j = x % 8;

		return _bits[i] & (1 << j);//本质就是在判断对应的那个位置是1还是0,只要不是0,那么就是真(true)例:00111100 & 00010000 => 00010000 ,虽然不是1,但是肯定不是0,所以返回true,只有当 00101111 & 00010000这种情况,当对应位置为0,那么就会返回false
	    //同理写法_bits[i] >> j & 1;  //但是要注意运算符的优先级
	}

private:
	vector<char> _bits;
};

void test_bitmap()//切记类名哪里都可以使用,需要指明类域的是该类里面的公共成员函数,但是可以直接使用类型构造对象使用
{
	bitmap<100> bm;//此时传的模板参数是100,结合上述代码表示的就是开辟100个比特位的空间(并且注意:此时一个比特位表示的就是存储一个整形数据)
	bm.set(12);//这个表示的就是将12按照比特位的形式表示出来,也就是上述的00010000  -->  16   --> 10
	bm.set(11);//00011000    -->    24    --> 18
	bm.set(15);//10011000    -->    152   --> 98(16进制)

	bm.reset(15);

	cout << bm.test(12) << endl;
	cout << bm.test(15) << endl;

	//如何直接将空间开到最大
	bitmap<-1> bm1;//此时类似之前学习的npos(反正表示的就是一个43亿左右的数),也就是表示此时在对应的位图中可以映射出了43亿个数据

}

//2.位图有关的变形问题(在100亿个数据中找只出现一次的数据)

template<size_t N>
class twobitmap
{
public:
	void set(size_t x)
	{
		if (_bm1.test(x) == false && _bm2.test(x) == false)
		{
			_bm2.set(x);//00->01   //满足该条件,就说明该数据是第一次出现,此时我们只要将该数据映射的位图置成1就行
		}
		else if (_bm1.test(x) == false && _bm2.test(x) == true)
		{
			_bm1.set(x);
			_bm2.reset(x); //01->10   满足该条件,就说明,该数据出现了一次以上,此时就只要将对应的位图由01(只出现了一次),置成10(出现了多次)就行
		}
		else
		{
			//10   多次出现
		}
	}
	void print()//打印只出现一次的值
	{
		for (size_t i = 0; i < N; i++)//遍历43亿个数
		{
			if (_bm2.test(i) == 1)//此时表示的就是01结果(表示该数据只出现了一次)
			{
				cout << i << endl;
			}
		}
	}
private:
	bitmap<N> _bm1;//直接去封装上面的,实现两个不一样的就行,00表示该数据没有出现,01表示该数据只出现了一次,10表示该数据出现多次
	bitmap<N> _bm2;
};
void test_twobitmap()
{
	int arr[] = { 3,6,8,10,45,67,90,5,144,6,1,0,22,222,67,14 };//注意:这个位置给值的时候要小心越界访问
	twobitmap<1000> bm;
	for (auto e : arr)
	{
		bm.set(e);
	}

	bm.print();
}

到了这里,关于Learning C++ No.26 【深入学习位图】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Learning C++ No.29 【右值引用实战】

    北京时间:2023/6/7/9:39,上午有课,且今天是周三,承接之前博客,今天我又去帮我舍友签到早八,但愿这次不会被发现吧!嘻嘻嘻!并且刚刚发文有关对C++11相关知识,由于所剩时间不多,这里我们就简单的为下篇博客,当然也就是该篇博客打一打铺垫,哦!对了,今天是高

    2024年02月08日
    浏览(45)
  • Learning C++ No.24 【哈希/散列实战】

    北京时间:2023/5/20/7:30,周六,可惜有课,而且还是早八,说明我们现在没有多少的学习时间啦!得抓紧把该博客的引言给写完,我们距离期末考越来越近啦!再过一个星期就要开始停课,然后进行什么实训,目前推测,这个实训估计就是在摆烂中摆烂,不过没有关系,只要

    2024年02月06日
    浏览(44)
  • Learning C++ No.28 【C++11语法实战】

    北京时间:2023/6/5/9:25,今天8点45分起床,一种怎么都睡不够的感觉,特别是周末,但是如果按照我以前的睡觉时间来看,妥妥的是多睡了好久好久,并且昨天也睡了一天,哈哈哈,睡觉这方面,真的睡能比我强,昨天是实训课,课程内容主要就是做一些C语言二级的题目,虽

    2024年02月08日
    浏览(42)
  • Learning C++ No.27 【布隆过滤器实战】

    北京时间:2023/5/31/22:02,昨天的计算机导论考试,三个字,哈哈哈,摆烂,大致题目都是一些基础知识,但是这些基础知识都是非常非常理论的知识,理论的我一点不会,像什么操作系统的分类,什么IP地址的计算,什么网络协议,反正是什么都不会,而且还有什么填空题,

    2024年02月07日
    浏览(52)
  • Learning C++ No.19【搜索二叉树实战】

    北京时间:2023/5/2/9:18,五一放假第四天,昨天本来想要发奋图强将该篇博客写完,但是摆烂了一天,导致已经好几天没有码字,敲代码了,此时难受的感觉涌上心头,但是摆烂的时候确实是快乐的,所以快乐总是建立在痛苦之上这句话是非常的正确的,谁让我们生而为人呢?

    2024年02月03日
    浏览(41)
  • Learning C++ No.30 【lambda表达式实战】

    北京时间:2023/6/9/9:13,今天8:15起床,可能是最近课非常少,导致写博客没什么压力,什么时间都能写,导致7点起不来,哈哈哈,习惯睡懒觉了,但是问题不大,还在可控范围内,并且就在前天下午,我们进行了学校MySQL的期末考试,大一就学MySQL,我甚是想吐糟,实操题对于

    2024年02月08日
    浏览(50)
  • Learning C++ No.22【二叉树OJ题实战】

    北京时间:2023/5/7/8:13,还是那句话,周末不摆烂,从我做起,昨日突下大雨,狂风呼啸,大雨倾盆,雷声隆隆,但依然没有打扰到我的美梦,睡的要多香就有多香,虽然现在依然很困,哈哈哈!也许是我自认为自己睡得很香,哈哈哈,今天有羽毛球打算,但是具体还得看情况

    2024年02月05日
    浏览(38)
  • 学习系统编程No.26【信号处理实战】

    北京时间:2023/6/26/13:35,昨天12点左右睡觉,本以为能和在学校一样,7点左右起床,设置了7点到8点30时间段内的4个闹钟,可惜没想到啊,没醒,直接睡到了12点,看来下次不能给自己太高的期望,哈哈哈!在家没办法呀,习惯睡到12点了,想要解决这个问题,最好的方法就是

    2024年02月11日
    浏览(46)
  • Learning C++ No.23【红黑树封装set和map】

    北京时间:2023/5/17/22:19,不知道是以前学的不够扎实,还是很久没有学习相关知识,对有的知识可以说是遗忘了许多,以该篇博客有关知识为例,我发现我对迭代器和模板的有关知识的理解还不够透彻,不知道是对以前知识的遗忘,还是现在所学确实有难度,反正导致我很懵

    2024年02月05日
    浏览(50)
  • 【C++学习】哈希的应用—位图与布隆过滤器

    文章简介 : 在这篇文章中,你会学习到关于哈希思想的最常见的两个应用,也就是 位图 与 布隆过滤器 , 文章会讲解位图和布隆过滤器的概念,底层实现,对应的适应的场景,以及相关经典 海量数据面试题 及解析。 所谓位图,就是用每一位来存放某种状态,适用于 海量

    2024年04月14日
    浏览(61)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包