【C++】位图应用 | 布隆过滤器

news2024/11/20 1:35:40

文章目录

  • 1. 位图应用
    • 题目一
      • 代码实现
        • set
        • rset
        • test
        • 具体代码
    • 题目二
    • 位图优缺点总结
  • 2. 布隆过滤器
    • 提出背景
    • 概念
    • 具体实现
      • hash1 hash2 hash3
      • N取值问题
      • set
      • tset
      • tset中在与不在那个准确?
      • 使用场景及特点
      • 具体代码

1. 位图应用

题目一

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


正常思路:
1.排序 + 二分查找
2.放入 哈希表 或者 红黑树


10亿字节 约等于 1GB
40亿个整数约等于 16GB
如果使用上述的两种方法,内存不够


哈希 的 直接定址法 的 哈希映射 ,判断整形在不在
依次映射标记,将值存起来
最少用一个char来表示一个值在不在 ,这样即为40亿字节即4GB,但是这样还是太大
标识在不在,并不需要将值存起来,使用0/1去表示


将每一个整数 所代表的值 用一个比特位去标识 即 位图
需要40亿个比特位,10亿字节 约等于 1GB ,40亿个比特位 约等于 500MB

代码实现

在bitset类中,
通过控制char,从而控制比特位


set

set 将x映射的比特位设置成1

由于下标从0开始计算
所以将0-7比特位算位第0个char ,8-15算为第1个char中,依次存储到对应的char
先计算在第几个char中,在计算在对应char的第几个比特位上面



j 代表要寻找对应比特位的位置 ,想要将其置为1
<<是低到高的移位
1<<j 即 除了j位置 其他位置 都为0

所以 | 1 ,无论该位置的数为1/0 ,|后都为1

rset

rset将x映射的比特位设置成0


j 代表要寻找对应比特位的位置 ,想要将其置为 0
所以 &0 ,无论该位置的数为1/0 ,&后都为0

test

test 判断在不在




j 代表要寻找对应比特位的位置 将当前位置值 &1
由于在其他位置上也有可能存在11,所以结果不为0,则说明该位置存在
若结果为0, 则说明该位置不存在

具体代码

template<size_t N>
class bitset
{
public:
	bitset()
	{
		_bits.resize((N / 8) + 1, 0);
	}
	void set(size_t x)
	{
		size_t i = x / 8;//第几个char上
		size_t j = x % 8;//char上的第几个比特位
		_bits[i] |= (1 << j);
	}
	void rset(size_t x)
	{
		size_t i = x / 8;//第几个char上
		size_t j = x % 8;//char上的第几个比特位
		_bits[i] &= ~(1 << j);
	}
	bool test(size_t x)//判断在不在
	{
		size_t i = x / 8;//第几个char上
		size_t j = x % 8;//char上的第几个比特位
		return _bits[i] & (1 << j);
	}
private:
	vector<char> _bits;
};

题目二

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


用 2个比特位表示 当前数据
00 表示 0次 01 表示 1次 10 表示 1次以上


将题目一的代码进行封装即可



题目一的类为bitset,所以借此 来定义出 两个比特位 _bs1 _bs2
通过判断 两个比特位 是 1 /0
若出现次数为0,则 +1 变为 0 1
若出现次数为1 , 则+1 变为 1 0
若出现次数为1次以上,则不变
最终通过类中的print函数打印出出现一次的数

位图优缺点总结

优点:

速度快 节省空间

缺点:
只能映射整形,string 浮点数 不能存储映射


所以提出布隆过滤器,用于一定程度解决 不能存储string类型的问题

2. 布隆过滤器

提出背景

用哈希表存储 缺点:浪费空间

用位图存储 缺点: 位图一般只能处理整形,若为字符串,则无法处理
将哈希与位图结合 即布隆过滤器

概念

用多个哈希函数,将一个数据映射到位图结构中
既可以提升效率,又可以节省大量空间


假设两个字符串映射到同一个位置,则会导致哈希冲突
布隆过滤器 想要 降低冲突概率
一个值映射到一个位置,容易误判,一个值映射到多个位置,就可以降低误判率


使用多种哈希映射算法,映射到不同的位置
如:每个值都映射到2个位置

具体实现

传递模板时,传入hash1 hash2 hash3 ,将K类型转换为整形
hash1 hash2 hash3 作为三种不同的映射方法

hash1 hash2 hash3

BKDRHash算法在哈希中的 针对string情况使用过 ,
当需使用字符串转化为整形时,将字符串中所有字符相加 ,用此确定对应的key
将BKDRHash作为缺省值 ,传给 hash1

点击查看详细解释:哈希


将APHash作为缺省值 ,传给hash2


将DJBHash作为缺省值 ,传给hash3


APHash 算法与 DJBHash 算法 是依据数学推导而来的
点击链接查看APHash 算法以及 DJBHash 算法的 具体解释: 哈希算法


N取值问题

N代表最多插入key数据的个数


k为哈希函数个数,m为布隆过滤器长度,n为插入元素个数

当k为3时, 3= ( m/n ) *0.69,m=4.3n
m越等于4n
布隆过滤器的长度 约等于 插入元素个数的4倍


set

_bs作为题目一的实现的位图结构
通过调用对应hash1 hash2 hash3中的operator() 的不同实现
将传入对应的字符串转换为不同的整形,在使用位图插入在不同的映射位置


tset

只有当hash1 hash2 hash3 三个不同的位置都在,它才在,若有一个位置不在,则它就不在


就算是两个字符串的ASCII值相同,但是顺序不同,在对应hash1 hash2 hash3 的对应映射位置也是不同的

tset中在与不在那个准确?

不在是准确的,当不在时,当前映射位置为0,若数据存在不可能使映射位置为0


在是不准确的,

ts本来在检查位置是不存在的,但是由于其他字符串发生冲突,正好将其要对ts检查的位置映射了,就会误以为ts存在,导致误判


使用场景及特点

能容忍误判的场景
如:快速判断昵称是否使用过
昵称有可能是由于误判,导致可能创建重复的,但是并不会有什么影响存在


正常来说,手机号是不能放入布隆过滤器中的,若使用有可能误判, 没有注册过,显示用户存在

在这里插入图片描述

但是布隆过滤器也是可以做到的,
若当前数据不在,则直接返回false
若当前数据在,有可能存在误判问题,所以去数据库中查找,若在则直接返回数据存在,若不在,则返回false


布隆过滤器的特点
优点:快,节省内存
缺点:存在误判 (数据在)

具体代码

#include<iostream>
using namespace std;
#include<vector>


template<size_t N>
class bitset
{
public:
	bitset()
	{	
		_bits.resize((N / 8) + 1, 0);
	}
	void set(size_t x)
	{
		size_t i = x / 8;//第几个char上
		size_t j = x % 8;//char上的第几个比特位
		_bits[i] |= (1 << j);
	}
	void rset(size_t x)
	{
		size_t i = x / 8;//第几个char上
		size_t j = x % 8;//char上的第几个比特位
		_bits[i] &= ~(1 << j);
	}
	bool test(size_t x)//判断在不在
	{
		size_t i = x / 8;//第几个char上
		size_t j = x % 8;//char上的第几个比特位
		return _bits[i] & (1 << j);
	}
private:
	vector<char> _bits;
};

void test_bitset()
{
	bitset<100> v;
	v.set(10);
	cout << v.test(10) << endl;
	cout << v.test(15) << endl;
}

//仿函数
struct BKDRHash
{
	size_t operator()(const string& s)
	{
		size_t hash = 0;
		for (auto e : s)
		{
			hash += e;
			hash *= 31;
		}
		return hash;
	}
};

struct APHash
{
	size_t operator()(const string& s)
	{
		size_t hash = 0;
		for (long i = 0; i < s.size(); i++)
		{
			size_t ch = s[i];
			if ((i & 1) == 0)
			{

				hash ^= ((hash << 7) ^ ch ^ (hash >> 3));
			}
			else
			{
				hash ^= (~((hash) << 11) ^ ch ^ (hash >> 5));
			}
		}
		return hash;
	}
};

struct DJBHash
{
	size_t operator()(const string& s)
	{
		size_t hash = 5381;
		for (auto e : s)
		{
			hash += (hash << 5) + e;
		}
		return hash;
	}
};


template< size_t N,
	class K = string,
	class Hash1 = BKDRHash,
	class Hash2 = APHash,
	class Hash3 = DJBHash>
class	BloomFilter  //布隆过滤器
{
public:
	void set(const K& key)
	{
		size_t len = N * _X; //整体长度
		//将其转换为可以取模的整型值
		size_t hash1 = Hash1()(key) % len;
		_bs.set(hash1);

		size_t hash2 = Hash2()(key) % len;
		_bs.set(hash2);

		size_t hash3 = Hash3()(key) % len;
		_bs.set(hash3);
	}

	//判断在不在
	bool test(const K& key)
	{
		size_t len = N * _X; //整体长度

		//三个位置都在才在,有一个位置不在 则不在
		size_t hash1 = Hash1()(key) % len;
		if (!_bs.set(hash1))
		{
			return false;
		}

		size_t hash2 = Hash2()(key) % len;
		if (!_bs.set(hash2))
		{
			return false;
		}

		size_t hash3 = Hash3()(key) % len;
		_bs.set(hash3);
		if (!_bs.set(hash3))
		{
			return false;
		}
		return true;
	}
private:
	static const size_t _X = 4;//整数倍
	bitset<N* _X> _bs;
};

// 一般是字符串才使用 布隆过滤器
// 所以默认使用字符串类型
void test_BloomFilter()
{
	BloomFilter<100> v;
	v.set("sort");
	v.set("left");
	v.set("right");
	v.set("hello world");
	v.set("test");
	v.set("etst");

}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

压缩感知重构之凸松弛法

算法的重构是压缩感知中重要的一步&#xff0c;是压缩感知的关键之处。因为重构算法关系着信号能否精确重建&#xff0c;国内外的研究学者致力于压缩感知的信号重建&#xff0c;并且取得了很大的进展&#xff0c;提出了很多的重构算法&#xff0c;每种算法都各有自己的优缺点&a…

Linux-地址空间

文章目录 问题引入操作系统宏观认识操作系统与进程程序地址空间进程地址空间问题解释 问题引入 在Linux操作系统中、vim编译器下&#xff0c;出现了变量同地址但不同值的现象。 下面以解释该现象产生的原因为主线&#xff0c;在过程中学习Linux操作系统的知识。 运行代码展示…

chatgpt赋能python:Python分词处理

Python分词处理 随着网络技术的飞速发展&#xff0c;搜索引擎已成为人们了解信息的主要渠道之一&#xff0c;而搜索引擎的核心是关键词匹配&#xff0c;因此分词技术在搜索引擎优化&#xff08;SEO&#xff09;中起着至关重要的作用。Python作为一种强大的编程语言&#xff0c…

【学习日记2023.6.3】之 工作台显示和报表导出

文章目录 12. 工作台显示和报表导出12.1 工作台12.1.1 需求分析和设计12.1.2 代码开发Controller层Service层接口Service层实现类Mapper层 12.1.3 功能测试12.1.4 提交代码 12.2 Apache POI12.2.1 介绍12.2.2 入门案例12.2.2.1 将数据写入Excel文件12.2.2.2 读取Excel文件中的数…

Linux4.7Nginx优化与防盗链

文章目录 计算机系统5G云计算第六章 LINUX Nginx优化与防盗链一、Nginx服务优化和深入优化1.隐藏版本号2.修改用户与组3.缓存时间4.日志切割5.连接超时6.更改进程数7.配置网页压缩8.配置防盗链9.fpm参数优化 计算机系统 5G云计算 第六章 LINUX Nginx优化与防盗链 一、Nginx服…

操作系统复习4.1.0-文件管理结构

定义 一组有意义的信息的集合 属性 文件名、标识符、类型、位置、大小、创建时间、上次修改时间、文件所有者信息、保护信息 操作系统向上提供的功能 创建文件、删除文件、读文件、写文件、打开文件、关闭文件 这6个都是系统调用 创建文件 创建文件时调用Create系统调用…

django中使用celery

Celery介绍&#xff1a; 核心及优点&#xff1a;1.基于分布式系统架构&#xff08;负载均衡避免单点故障&#xff0c;高可用&#xff09; 2.实现了异步任务的调度&#xff08;快速&#xff09; 只需要通过配置文件的修改就可以实现架构的切换所以灵活 django-celery-beat 用…

Oracle中的循环

目录 一、简单循环 1.1LOOP 循环语法&#xff1a; 1.2LOOP 循环示例 二、for循环 2.1for循环语法&#xff1a; 2.2for循环示例 三、while循环 3.1while循环语法 3.2while循环示例 四、GOTO 循环 4.1GOTO 循环语法 4.2GOTO 循环示例 在 Oracle 数据库中&#xff0c;…

储能之动力电池与储能电池区别?

储能之动力电池与储能电池区别 1、概念1.1 动力电池1.2 储能电池 2、应用场景3、动力电池与储能电池的对比3.1 性能要求3.2 循环次数3.3 电池类型方面3.4 成本结构不同 1、概念 1.1 动力电池 动力电池即为工具提供动力来源的电源&#xff0c;多指为电动汽车、电动列车、电动自…

Oracle中ORA-12560:协议适配器错误

平时在长时间未登录Oracle数据库&#xff0c;再次登录时会出现如下错误&#xff1a; 当Oracle登录时出现12560协议适配器错误时&#xff0c;可以通过以下步骤尝试启动相应的服务&#xff1a; 第一步&#xff1a; 打开本地【服务】&#xff0c;点击最顶层的名称输入【O】&…

java-字符流和字节流(三)

java-字符流和字节流(三) 一、IO特殊操作流 1.1 标准流 1.1.1 标准输入流 System类中有两个静态的成员变量 public static final InputStream in&#xff1a;标准输入流。通常该流对应于键盘输入或由主机环境或用户指定的另一个输入源public static final PrintStream out&am…

【StringBuilder类】添加和反转方法以及StringBuilder和String相互转换

StringBuilder类 如果对字符串进行拼接操作&#xff0c;每次拼接都会构建一个新的String对象&#xff0c;既耗时又浪费内存空间&#xff0c;而这种操作还不可避免。我们可以通过Java提供的StringBuilder类来解决这个问题。StringBuilder是一个可变的字符串类&#xff0c;我们可…

java-基础语法(一)

java-基础语法(一) 一、java变量 1.1、注释 单行注释 // // 这是单行注释文字多行注释 /* *//* 这是多行注释文字 这是多行注释文字 这是多行注释文字 */ 注意&#xff1a;多行注释不能嵌套使用。1.2 常量 常量&#xff1a;在程序运行过程中&#xff0c;其值不可以发生改变的…

Arthas-monitor/watch/trace 相关命令使用

tip&#xff1a;作为程序员一定学习编程之道&#xff0c;一定要对代码的编写有追求&#xff0c;不能实现就完事了。我们应该让自己写的代码更加优雅&#xff0c;即使这会费时费力。 开头&#xff1a; 本章所有的命令都非常重要&#xff0c;都是使用率相当高的。 文章目录 moni…

python---列表

列表 1. 列表的介绍1.1 访问列表元素1.2 索引从0而不是1开始1.3 使用列表中的各个值1.4 修改、添加和删除元素1.4.1 修改列表元素 1.5 在列表中添加元素1.5.1 在列表末尾添加元素1.5.2 在列表中插入元素 1.6 从列表中删除元素1.6.1 使用方法pop()删除元素1.6.2 弹出列表中任何位…

【TreeSet集合】自然排序Comparator的使用

自然排序Comparator的使用 存储学生对象并遍历&#xff0c;创建TreeSet集合使用无参构造方法 要求&#xff1a;按照年龄从小到大排序&#xff0c;年龄相同时&#xff0c;按照姓名的字母顺序排序 创建学生类&#xff1a; package com.gather.set.treeset; public class Student…

【利用AI让知识体系化】前端开发学习了解业务架构

文章目录 I. 前端技术入门1.1 HTML/CSS/Javascript 简介1.2 前端框架 React/Vue/Angular 了解1.3 前端工具 Git/Webpack/npm/yarn 的使用1.4 前端调试和性能优化技巧 II. 开发综合应用2.1 工程化开发的全流程2.2 单页面应用 (SPA)2.3 数据交互和批量操作2.4 模块化和组件化开发…

压缩感知重构之匹配追踪算法

算法的重构是压缩感知中重要的一步&#xff0c;是压缩感知的关键之处。因为重构算法关系着信号能否精确重建&#xff0c;国内外的研究学者致力于压缩感知的信号重建&#xff0c;并且取得了很大的进展&#xff0c;提出了很多的重构算法&#xff0c;每种算法都各有自己的优缺点&a…

[golang 微服务] 4. gRPC介绍,Protobuf结合gRPC 创建微服务

一.gRPC框架的介绍 简介 gRPC是一个 高性能、 开源和 通用的 RPC 框架&#xff0c; 面向移动端和 HTTP/2 设计,目前提供 C、Java 和 Go语言版本&#xff0c;分别是&#xff1a;grpc, grpc-java, grpc-go,其中 C 版本支持 C, C, Node.js, Python, Ruby, Objective-C, PHP 和 C# …

Windows Pyqt5配置环境过程(pycharm Anaconda)

必要安装 Anaconda下载地址 Pycharm下载地址 这两个推荐2019年左右的版本就行了&#xff0c;安装的时候选择“add path” Anaconda换源 换源之后叉掉终端之后再创建环境 Anaconda常用命令 Anaconda换源应该是只对conda install 有用&#xff0c;pip还要换源 使用清华源进行…