位图

位图
1.位图的概念

所谓位图,就是用每一位来存放某种状态,适用于海量数据,数据无重复的场景,通常是用来判断某个数据存不存在的。

2.位图的实现
namespace BitSet
{
	class bitset
	{
	public:
		bitset(size_t n)
		{
			_bit.resize(n / 32 + 1, 0);
			_num = 0;
		}
		void set(size_t x)
		{
			size_t index = x / 32;
			size_t pos = x % 32;
			_bit[index] |= (1 << pos);
			++_num;
		}
		void reset(size_t x)
		{
			size_t index = x / 32;
			size_t pos = x % 32;
			_bit[index] &= ~(1 << pos);
			--_num;
		}
		bool test(size_t x)
		{
			size_t index = x / 32;
			size_t pos = x % 32;
			return _bit[index] & (1 << pos);
		}
	private:
		vector<int> _bit;
		size_t _num;
	};
}
位图的应用

a.快速查找某个数据是否在一个集合中。

b.排序。

c.求两个集合的交集,并集等。

d.操作系统中磁盘块标记。

3.布隆过滤器
3.1布隆过滤器的提出

我们在使用客户端看视频时,它会给我们不停地推荐新的内容,它每次推荐时要去重,去掉已经看过的内容。服务器会记录用户看过的所有历史记录,当推荐系统推荐时会从每个用户的历史记录中进行筛选,过滤掉哪些已经存在的记录。

a.用哈希表存储用户记录浪费空间。

b.用位图存储用户记录不能处理哈希冲突。

c.将哈希和位图结合起来:布隆过滤器。

3.2布隆过滤器的概念

布隆过滤器是一种比较紧凑型的、比较巧妙的概率型数据结构,特点是高效地插入和查询,判断某样东西存不存在,他是用多个哈希函数将一个数据映射到位图结构中,不仅可以提升查询效率。也可以节省大量的内存空间。

3.3布隆过滤器的实现
#pragma once
#include"bitset.h"
namespace BloomFilter
{
	struct HashStr1
	{
		size_t operator()(const string &s)
		{
			size_t ret = 0;
			for (size_t i = 0; i < s.size(); i++)
			{
				ret *= 131;
				ret += s[i];
			}
			return ret;
		}
	};
	struct HashStr2
	{
		size_t operator()(const string& s)
		{
			size_t ret = 0;
			size_t magic = 63689;
			for (size_t i = 0; i < s.size(); i++)
			{
				ret *= magic;
				ret += s[i];
				magic *= 378551;
			}
			return ret;
		}
	};
	struct HashStr3
	{
		size_t operator()(const string& s)
		{
			size_t ret = 0;
			for (size_t i = 0; i < s.size(); i++)
			{
				ret *= 65599;
				ret += s[i];
			}
			return ret;
		}
	};
	template<class K = string, class Hash1 = HashStr1, class Hash2 = HashStr2, class Hash3 = HashStr3>
	class bloomfilter
	{
	public:
		bloomfilter(size_t num)
			:_bs(5 * num)
			, _num(5 * num)
		{}
		void set(K key)
		{
			size_t index1 = Hash1()(key) % _num;
			size_t index2 = Hash2()(key) % _num;
			size_t index3 = Hash3()(key) % _num;
			_bs.set(index1);
			_bs.set(index2);
			_bs.set(index3);
		}
		bool test(K key)
		{
			size_t index1 = Hash1()(key) % _num;
			if (_bs.test(index1) == false)
				return false;
			size_t index2 = Hash2()(key) % _num;
			if (_bs.test(index2) == false)
				return false;
			size_t index3 = Hash3()(key) % _num;
			if (_bs.test(index3) == false)
				return false;
			return true;
		}
	private:
		bitset _bs;
		size_t _num;
	};
}
3.4布隆过滤器优点

a.增加和查询元素的时间复杂度为:O(K), (K为哈希函数的个数,一般比较小),与数据量大小无关。

b.哈希函数相互之间没有关系,方便硬件并行运算。

c. 布隆过滤器不需要存储元素本身,在某些对保密要求比较严格的场合有很大优势。

d.在能够承受一定的误判时,布隆过滤器比其他数据结构有这很大的空间优势。

e.数据量很大时,布隆过滤器可以表示全集,其他数据结构不能。

f.使用同一组散列函数的布隆过滤器可以进行交、并、差运算。

3.5布隆过滤器缺陷

a.有误判率,即不能准确判断元素是否在集合中。

b.不能获取元素本身。

c.一般情况下不能从布隆过滤器中删除元素。

d.如果采用计数方式删除,可能会存在计数回绕问题。

4.海量数据处理
1.给定100亿个整数,设计算法找到只出现一次的整数。

数据的出现次数分为三种:出现0次,出现1次,出现2次及以上。

我们使用两个位表示一个整数,00为0次,01为1次,10为2次及以上。

2.给两个文件,分别有100亿个整数,1G内存如何找到交集。

方案1:将其中一个文件的整数映射到一个位图中,读取另外一个文件中的整数,判断在不在位图,在就是交集,消耗500M内存。

方案2:将文件A的整数映射到位图1,文件B的整数映射到位图2,两个位图按位与,与之后为1的位就是交集,消耗1G内存。

3.一个文件用100亿个int,1G内存,设计算法找到出现次数不超过两次的所有数字。

和第一题思路差不多,还是用两个位表示一个整数,00为0次,01为1次,10为2次,11为3次及以上。

4.给两个文件,分别有100亿个query,只有1G内存,找到两个文件的交集。

平均一个query30-60字节,100亿个query大约占用300-600G。

近似算法:将文件A中的query映射到一个布隆过滤器,读取文件B中的query,判断在不在布隆过滤器中,在就是交集。但是交集中有些数不准确。

精确算法:把两个文件A和B进行哈希切分(i=hashsrt(query)%1000)为多个小文件,i是多少query就进入第Ai/Bi的小文件中。A和B中相同的query一定进入编号相同的Ai和Bi小文件,只需要编号相同小文件找交集就可以。

5.如何扩展布隆过滤器使得它支持删除元素的操作。

每个位标记成计数器。

如果给的位少了,多个值映射到一个位置会导致计数器溢出。比如一个字节最多计数搭配256,如果有257个值都映射到了一个位置,就出问题了。但使用更多的位映射一个位置,空间消耗就大了,布隆过滤器的特点是为了节省空间。

6.给一个超过100G大小的logfile,log中存着IP地址,设计算法找到出现次数最多的IP地址。

首先这里要做的是统计次数,统计次数我们一般用kv模型的map解决。先创建1000个小文件,A0~A999,读取IP计算出i=hashstr(IP)%1000。i是多少,IP就进入对应编号的Ai小文件,这样同一IP地址一定进入同一小文件。map<string, int>count读取Ai中的IP统计出次数,读完一个小文件就clear,再读另一个。使用pair<string, int>max记录出现次数最多的IP就可以求出。

5.一致性哈希

一般情况下,用户的信息存储在服务器(假设有10W个服务器)。如果一个用户要浏览和删除这条信息,一个到那台服务器去查找。这就需要用户和服务器建立一个映射关系(i=hashstr(Mrsw)%10W)。i是多少就存到第i号服务器(实际中可能需要一台额外的服务器存储服务器编号和IP的映射关系,这样子算出i就可以找到他的IP,就可以访问对应服务器了)。

上面的方案有一个很大的缺陷,随着用户数据越来越多,10W台服务器不够用了,我们要将服务器增加到15W台,之前的映射关系就不对了,需要重新计算位置迁移数据。解决这个缺陷就要用一致性哈希。
在这里插入图片描述

一致性哈希的映射关系是:i=hashstr(Mrsw)%2^32。用0~ 2^32-1中一段范围的值去映射一台服务器,整个段的范围就映射这10W台服务器。这是如果增加5W台服务器,不需要所以数据迁移,只需要迁移部分负载重的服务器上的数据。

一致性哈希就是给一个特别大的除数,就算增加服务器也不需要重新计算迁移。它是一段范围映射一台机器<x1~x2, IP>,那么增加机器只需要改变映射范围即可,且迁移小部分的数据。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值