中级C++:位图

本文介绍了位图的概念及其在处理海量数据时的优势,如快速查找、排序和集合运算。通过STL的`bitset`实现位图,并展示了如何利用位图解决寻找只出现一次的整数问题。同时,提出了哈希切分方法,用于处理大规模数据,如找出日志文件中最频繁出现的IP地址。测试用例验证了位图和哈希切分的有效性。
摘要由CSDN通过智能技术生成

位图概念

在这里插入图片描述

  • 哈希是给一个类型的数据,进行单个映射。当面对40亿个海量数据时,内存就存不下了。
    • 哈希桶一个 next 指针4个字节,单指针40亿个,160亿个字节。
  • 换算:160亿个字节。
    • 1个G 10亿多字节。40亿,4个G。16个G。
1 G = 1024MB  = 1024*1024 KB = 1024*1024*1024Byte
2^30   1 000 000 000   
10001000010 0000100 00001000 00001 0000 000010 0000 0000

位图

  • 数据是否在给定的整形数据中,结果是在或者不在,刚好是两种状态,
  • 那么可以使用一个二进制比特位来代表数据是否存在的信息,如果二进制比特位为1,代表存在,为0代表不存在。
  • 适用于海量数据,数据无重复的场景。通常是用来判断某个数据存不存在的。
  • 字节序,即字节在电脑中存放时的序列与输入(输出)时的序列是先到的在前还是后到的在前。
    在这里插入图片描述

位图的实现

  • 2^32 个比特位 可表示一个无符号整型的最大值4,294,967,295,也就是 512MB。
2^32 / 2^3  2^29  =  2^30 / 2   =  1G /2  =  512MB  

STL的容器:

在这里插入图片描述

size_t N 可变模板参数:根据数据范围,开多大的比特位。

  • 常用功能:
    • set,将一个数字设置成存在;
    • reset,将一个存在的数据设置成不存在;
    • test,看一个数字在不在。
  • 一个数据 / 8 就是 在哪个 数组 的下标里;% 8 ,是在哪个比特位上。
    在这里插入图片描述
#include<iostream>
#include<vector>
#include<time.h>
using namespace std;
namespace mybitset  //处理整数  STL容器 bitset
{ 
	//按位申请空间
	template<size_t N>
	class bitset
	{
	public:
		bitset()
		{
			_vc.resize(N / 8 + 1,0);//多开一个字节,2/8 不给开
		}
		//该比特位设置成 1,在
		void set(size_t  x)
		{
			//在第几个char对象里
			size_t i = x / 8; 
			//锁定在char对象里第几个比特位。
			size_t j = x % 8;
			_vc[i] |= (1 << j);
		}
		//将该数字设置成不存在
		void reset(size_t x)
		{
			size_t i = x / 8;
			size_t j = x % 8;

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

		//探测该数字在不在
		bool test(size_t x)
		{
			size_t i = x / 8;
			size_t j = x % 8;

			return (_vc[i] & (1 << j)) == 0 ? false : true;
			/*if ((_vc[i] & (1 << j)) == 0)
			{
				return false;
			}
			else
			{
				return true;
			}*/
		}
	private:
		vector<char> _vc;
	};

位图应用

  1. 快速查找某个数据是否在一个集合中
  2. 排序
  3. 求两个集合的交集、并集等
  4. 操作系统中磁盘块标记

给定100亿个整数,设计算法找到只出现一次的整数?复用位图:给两个位图

template<size_t N>
	class find_once_num
	{
	public:
		find_once_num()
		{}
		void set(size_t x)
		{
			bool flag1=_bt1.test(x);
			bool flag2 = _bt2.test(x);
			if (flag1==false && flag2==false)//00--> 01 
			{
				_bt2.set(x);
			}
			else if (flag1 == false && flag2 == true) // 01 已经出现一次;设置成10:代表出现两次
			{
				_bt1.set(x);
				_bt2.reset(x);
			}//10-->11出现多次
		}
		void prinf()
		{
			for (size_t i = 0; i < N; i++)
			{
				bool flag1 = _bt1.test(i);
				bool flag2 = _bt2.test(i);
				if (flag1 == false && flag2 == true)
				{
					cout << i << " ";
				}
			}
			cout << endl;
		}
	private:
		bitset<N> _bt1;
		bitset<N> _bt2;
	};

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

  • 位图应用变形:1个文件有100亿个int,1G内存,设计算法找到出现次数不超过2次的所有整数
    在这里插入图片描述

哈希切分

给一个超过100G大小的log file, log中存着IP地址, 设计算法找到出现次数最多的IP地址? 与上题条件相同,如何找到top K的IP?

思路:

  • 建立100个小文件,等于是100个哈希桶;100G文件依次获取ip地址,ip地址是字符串,算法转成int % 100 ,相同的,冲突的都到一个文件里面。
  • 再依次读取每个小文件;map<string,int> map[ ip ]++ ,这里的ip地址就是大文件里该ip出现的总次数;给一个max,记录单个文件出现次数最多的那个pair.
  • 然后clear掉map,换下一个文件。
  • 对所有小文件的max进行优先级队列按pair<int,string>插入,取top,K–。
  • 若某个小文件过大,换个字符串转换算法,再切分。

测试用例

	void test()
	{
		int a[] = { 5,6,6,7,8 };
		find_once_num<10> f1;
	/*	srand(time(0));
		for (size_t i = 0; i < 5; i++)
		{
			f1.set(rand()%100);
		}*/
		for (auto& i : a)
		{
			f1.set(i);
		}
		f1.prinf();
		cout << endl;
	}
	void test1()
	{
		bitset<10> b1;
		b1.set(9);
		cout << b1.test(9)<<endl;
	}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值