【数据结构/C++】位图

这里写自定义目录标题

  • 哈希思想的应用
  • 位图
  • 位图概念
    • 经典面试题
    • 位图所开的空间大小
    • STL库中的 `bitset` 位图
  • 位图实现
    • 大框架
    • 位运算符<<左移 和 >>右移 移动的方位
      • set():把x映射的位标记成1
      • set() 接口实现
      • reset:把x映射的位标记成0
      • reset() 接口
      • test():检测x位是1还是0
    • 效率
    • 海量面试题
  • 布隆过滤器
    • 布隆过滤器提出
    • 数据在内存中查找
    • 布隆过滤器的引入
    • 布隆过滤器
  • 布隆过滤器 实现
    • 大框架
      • 模板参数
    • 讨论1:哈希函数个数 的选择 —— 开`3`个哈希函数(一个值映射`3`个位)
    • 讨论2:布隆过滤器长度 —— 开要进行插入元素个数的`5`倍大小
    • reset() 删除 不能实现
  • 布隆过滤器 码源实现
    • 经典面试题
      • 对于 切分的文件数量多少 的讨论
      • 极端情况:某个文件冲突很多,导致`Ai`或者`Bi`太大了,比如超过1G,
    • `i=HashFunc(query)%100`哈希切分出各`Ai`文件 + `map<string, int>`统计次数 + `topK` `priority_queue`小堆 :统计出`topK的IP`地址
    • `i=HashFunc(query)%100`哈希切分成各`Ai`文件 + `map<int, int>` 逐一遍历哈希切分出的各`Ai`文件:统计出现的次数
    • 海量数据处理 问题的特征



哈希思想的应用

哈希(也叫 散列) 是一种 映射 的思想
哈希表:解决问题的思想(算法思想):哈希表通过映射这种思想,实现了哈希表这种数据结构

还有其他的数据结构:位图、布隆过滤器。小众点的,基数树(多阶哈希)



位图

位图概念

经典面试题

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

  1. 排序+二分
  2. set + find

1G=1024MB;1MB=1024KB;1KB=1024byte 。( 1024=2^ 10. )
1G=1024 * 1024 * 1024=(2^ 10)^ 3 = 2^ 30 byte
由此得出,1G就能存放1,000,000,000 (10亿)个数据。每一个数据存放的单位是1byte。
42亿 (即 2^32 ) 则需 4G 的数据大小(基本单位为 byte)通过位图,一个bit位便能 映射表示一个数(1byte=8bit),因此 开一个 能够映射42亿数据位图 所需的内存空间大小为 4G / 8bit = 0.5G (512M)


位图所开的空间大小

位图 开的大小,是按范围去开。无符号整数 的范围是 0~4,294,967,295,因此我们需要开0~4,294,967,295大的范围 。即使是100亿个数据,不管开多大还是开多小,都开Unsigned_int大小的位置, 除这42亿9千万个数外,其他的都是重复的

INT_MAX 大小是不够的才 2,147,483,647(因为是有符号整型,还有另一半 INT_MIN,所以为 2,147,483,647
2*INT_MAX:默认给出INT_MAX的时候识别是整型(int) * 2 以后会溢出 。因此要用UINT_MAX (unsigned_int_max)范围就是从0~4,294,967,295

bitset<> bs;

(size_t)-1 将-1强转为无符号整形
UINT_MAX (unsigned_intMAX)
0xffffffff(16进制:8个f)
pow(2,32)-1


倘若是通过数据结构来存储的, 4G(个数据) X 一个整数4byte = 总共16G-的内存大小 。排序需要连续的物理地址空间大小。平时普通的电脑内存根本不够用。像红黑树一个节点中存放三指针和一个数据,其所消耗的内存大小就更不用说了。

对于这道题目而言,一个数据只有两种状态:在/不在。如果我们想要标识两种状态,其实 只需要一个比特位就够了,0表示不存在,1表示存在通过哈希的映射思想,我们可以把每一个数据映射到一个比特位中,这就是位图的概念

  1. 开2^32个bit位【 按范围去开:Unsigned_int 42亿9千万
    表示一个数在或者不在,用一个bit比特位来表示


STL库中的 bitset 位图

简单了解bitset的最常用接口,明白其的功能有哪些,后面实现 。
在这里插入图片描述
类模板:
非类型模板参数N,位图中要开多少个比特位。

接口功能
operator[]返回对应位置的引用
count计算所有比特位中1的个数
size返回比特位的个数
test检测某一个位,是1返回true,是0返回false
set把某一个位的值改为1
reset把某一个位的值改为0


位图实现

大框架

template<size_t N>
class bitSet
{
public:private:vector<int> _bits;
};

模板参数N :用于传参,代表传过来的有多少个数需要判断N就是要开的bit位的数量

但位图的 底层结构是vector< int >int类型的数组 ),而 一个int有32个bit,一个位置能容下判断32个数。那么我们应开的空间为 N / 32int空间大小的vector<>

但由于C++的除法会向下取整,所以我们要额外+1避免开出来的位不够。如63/32=1,那剩下的31位怎么办?

这样我们就可以写一个构造函数 。

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


位运算符<<左移 和 >>右移 移动的方位

左移还是右移,是由大小端来决定的吗?大小端在内存窗口中查看。小端(低位在地址低位,高位在地址高位),大端(高位在地址低位,低位位在地址高位)

不是的,也没有说在小端机中右移是往高位移,左移往低位移这样的说法。
左移和右移并不是单纯的方向上的移动,而是统一 左移是往高位移,右移是往低位移 。而 硬件层 会单独判断处理数值是小端机还是大端机,(cpu)硬件体系中的指令体系 相当于 封装 了左移和右移,直接执行左移所对应的往高位移的操作,右移所对应的往低位移的操作



set():把x映射的位标记成1

大体逻辑:

  • 先定位( 一个元素有32个bit位 )
    • 确定是vector中的第i个元素
    • i个元素的第j个比特位
size_t i = x / 32; // vector的第i个元素
size_t j = x % 32; // 第i个元素的第j个比特位
  • 先将1左移<<(往高处移)到要标记成的位置( 除了该位置为1,其他位置都是0 )
  • 按位或等|= :有1则为1,( 除了该位置为1,其他位置都是0 )则能控制j位修改为1,而其他位置不受影响。

如把11001100的第4位变为1:

   11001100 	// 待修改数据00000001 	// 数字100010000 	// 数字1左移4位
------------11001100
|= 00010000 	// 按位或等------------11011100

set() 接口实现

	// 把x映射的位标记成1void set(size_t x){assert(x <= N);size_t i = x / 32;size_t j = x % 32;_bits[i] |= (1 << j);}


reset:把x映射的位标记成0

将改为设置成0:

  • 定位
  • 将除了该位置设置成0,其他都设置成1
    这要怎么做到呢?对上面将该位置标记成1的( 1<<j )进行 取反操作~,就得到该位置是0,其他位置都为1 的底部
  • 然后 &= 按位与等:有0则为0,将该为修改为0。(其他位置都是1,则不会受到影响)
   11011100  // 待修改数据00000001  // 数字100010000  // 数字1左移4位(1<<j)
-------------11011100~ 00010000  // ~取反
-------------11011100
&= 11101111  // 按位与&=: 0来修改1
-------------11001100 

reset() 接口

	// 把x映射的位标记成0void reset(size_t x){assert(x <= N);size_t i = x / 32;size_t j = x % 32;_bits[i] &= ~(1 << j);}


test():检测x位是1还是0

  • 左移1<<j( 让1与其按位与判断 )
  • & 按位与判断 就行了,不进行修改
    最后 return 该_bits[i]位的 整型值 转化成 bool值:0就是假,非0就是真。
bool test(size_t x)
{assert(x <= N);size_t i = x / 32;size_t j = x % 32;return _bits[i] & (1 << j);		// & 按位与判断,不进行修改
}


#include"BitSet.h" 展开在.cpp中,展开后BitSet.h里的内容也就只能向上查找
【链接】



效率

把数都遍历一遍,全都set到位图中。
剩下的查找就直接根据O(1),就能映射到要找的数据



海量面试题

  1. 给定100亿个整数,设计算法找到只出现一次的整数
  • 思路1:用map 内存存不下这些值
    10,000,000,000
    10亿多byte是1G,100亿多是10G,是整数因此还要x4byte,因此这里需要40G-的内存

  • 思路2:还是通过位图来映射找到对应数据出现的次数
    1次 和 2次及以上,需要2个比特位,只需要判断3中状态就可以了"00,01,10"(00 - 0次,01 - 1次,10 - 2次及以上)

    • 连开两个bit位,映射关系处理的有点麻烦
    • 直接开两个位图 ,两个位图组合起来就是其统计的次数
template<size_t N>
class two_bit_set
{
public:// 00 -> 01 1次// 01 -> 10 2次及以上(10以后就不变)void set(size_t x){// 00 -> 01if (_bs1.test(x) == false&& _bs2.test(x) == false){_bs2.set(x);}else if (_bs1.test(x) == false      && _bs2.test(x) == true)   {// 01 -> 10_bs1.set(x);_bs2.reset(x);}}void test(size_t x){// 00 if (_bs1.test(x) == false&& _bs2.test(x) == false){return 0;}else if (_bs1.test(x) == false&& _bs2.test(x) == true){// 01return 1;}else{return 2;   // 2次及以上}}private:bitSet<N> _bs1;bitSet<N> _bs2;
};

也可以按照自己的需求自己造轮子:

	// 根据需求自己造轮子:只需判断出只出现一次的bool test(size_t x){if (_bs1.test(x) == false&& _bs2.test(x) == true){// 01return true;}return false;}


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

思路:分别set到两个位图,两个位图同时为1,按位与& 后为1,则为交集

void test_bitset2()
{int a1[] = { 4,9,5 };int a2[] = { 9,4,9,8,4 };bitSet<100> bs1;bitSet<100> bs2;for (auto e : a1){bs1.set(e);}for (auto e : a2){bs2.set(e);}for (size_t i=0;i<100;i++){if (bs1.test(i) && bs2.test(i))    // 都存在{cout << i << endl;}}
}


  1. 位图应用变形:1个文件有100亿个int,只有512M内存,设计算法找到出现次数不超过2次的所有整数

    处理 Unsigned_int_max无符号整型(范围为0~42亿9千万),所需开的位图大小为 0.5G
    这里有100亿个int整型,则大概需要1G多的内存大小来处理数据,内存不够,怎么办?

    位图所开的空间大小,是取决于需要映射的数的范围 。 若只有512M的内存,则每次只映射一半范围的数据,因此则能一次只使用256M的内存(直接映射) 。第二次值统计,则统计后半部分(通过间接映射 x-2^31 )。

    将分开遍历的两组值,一个位图对这分开的两组值,分别都进行遍历 。



布隆过滤器

布隆过滤器提出

我们在使用新闻客户端看新闻时,它会给我们不停地推荐新的内容,它每次推荐时要去重,去掉那些已经看过的内容。问题来了,新闻客户端推荐系统如何实现推送去重的? 用服务器记录了用户看过的所有历史记录,当推荐系统推荐新闻时会从每个用户的历史记录里进行筛选,过滤掉那些已经存在的记录。 如何快速查找呢?

数据在内存中查找

  • 排序 + 二分查找:
    排序只需要排一次,后面的查找。
    不足:主要的问题是在 数组 上,插入在头部、中间都要挪动数据,消耗很大

  • 搜索树
    按照搜索树规则,搜索的时间复杂度为O(log_2 N)
    不足: 该数据结构 在内存大小上的消耗很大,一个节点存放三指针一数据。

  • 哈希表
    映射规则,
    不足:浪费空间,一个空间存储数据的大小根据要存储的数据通过 Hash哈希函数 转化成整型来进行哈希映射存储。整型大小的位为int

  • 位图(应用了哈希映射思想 + 位运算0 1 标记,仅需bit位的大小)
    局限:只是要简单判断这个值在不在 -> 只需要 位映射 来进行0 1标记,仅需bit位的大小

    • 特点:1. 快 ; 2. 节省空间

    • 不足只能解决整型

      只是要简单判断这个值在不在,就能用位图 位映射标记,直接查找该位置标记的值是0还是1来直接判断是否存在 的思想,来解决问题。



布隆过滤器的引入

若想将位图这样,只是想简单判断这个值在不在 的思想,同样应用在其他自定义类型上。

要是是其他类型,(如自定义类型,string类型,怎么办?)通过字符串来判断

若仍采用位图来解决string类 有可能会存在哈希冲突:
不同的字符串(无限) —> 整型(有限 42亿9千万) —> 映射存储位置 ,字符串的多少是无限多(假设开的位图大小是10个位置,这能组合出来的字符串是已经256^10个了,这远超 有限个整型个数),即一定会存在整型重复,而造成误判的情况存在。


误判:

  • 在:有误判的可能(本来不在,映射位置冲突了,误判成在了)
  • 不在:准确的


存在误判,但如果将要将这样的映射位置冲突的概率降低 。

布隆过滤器

一个数据插入多个位置,这多个位置,可能会存在映射和其他位置存在冲突,只要遍历到的该位置 不存在,则进行映射插入,则大大降低了映射冲突的概率。

在这里插入图片描述



布隆过滤器 实现

大框架

template<size_t N,       // 要插入数据的个数class K= string,	    // 常用于布隆过滤器的key值是stringclass Hash1	= HashFuncBKDR,       // Hash1,Hash2,Hash3 通过不同的Hash哈希,分别映射到不同的三个位置class Hash2 = HashFuncAP, class Hash3 = HashFuncDJB>
class  BloomFilter
{
public:private:bitSet<5*N> _bs;	   
};

模板参数

class K = String 缺省参数传string,因为最常传的类型是string 。K是指需要位图进行标识是否存在的数据的类型: 传 自定义类型(如 日期类),只要对应传对应自定义类型的仿函数(将其转化成整型) 就行

size_t N 需要进行存储在位图中,需要进行Hash哈希函数映射处理的数据个数:想要通过建立映射关系来达到O(1)的查找时间复杂度 。


布隆过滤器 的之所以能实现不同字符串之间不冲突,来实现自定义类型也能使用位图来达到O(1)查找的时间复杂度的直接映射,是通过实行多个哈希函数在位图中进行多个位置同时映射,来降低哈希冲突的概率从而让非整型类型也能采用哈希思想O(1)的时间复杂度直接判断出该数据是否存在。

但这样的实行 多个哈希函数 进行的 多个位置同时映射,来判断该数据是否存在的做法,对空间消耗非常大,因此 对于因为要建立这样多个映射关系,要开多大的布隆过滤器 也是有讲究的,下面让我们来进行一下讨论分析。



讨论1:哈希函数个数 的选择 —— 开3个哈希函数(一个值映射3个位)


哈希函数的个数(一个值映射几个位 的) 也需要权衡:

  • 个数越多 则布隆过滤器 bit 位置位 1 的速度越快,且布隆过滤器的效率越低
  • 但是如果太少的话,那我们的误报率会变高

在这里插入图片描述
k 为哈希函数个数(一个值映射几个位)m 为布隆过滤器长度(有多少个位),n 为插入的元素个数(数据个数),p 为误报率

由图可看出,当k==3时,就已经把 误报率p 由原来的1降低到接近0.01了。则映射位置再拉大,对误报率的降低也没差多少了。得出结论:一个值的映射位数,一般取3位,因此需三个映射函数。



讨论2:布隆过滤器长度 —— 开要进行插入元素个数的5倍大小

x为哈希函数的个数,m是布隆过滤器的长度,n是插入元素的个数。经过研究发现,三者满足以下关系式时,布隆过滤器的误判率最低:

x = m / n ∗ l n 2 x=m/n * ln2 x=m/nln2

由上得出的 哈希函数个数x 的 最优数量大小是3,那么我们所开的布隆过滤器的长度大小m 大约是 插入元素的个数n4.3 。因此我们自己模拟实现布隆过滤器我们取整数5倍:bitset<5 * N> _bs;

template<size_t N,       // 要插入数据的个数class K= string,	    // 常用于布隆过滤器的key值是stringclass Hash1	= HashFuncBKDR,       // Hash1,Hash2,Hash3 通过不同的Hash哈希,分别映射到不同的三个位置class Hash2 = HashFuncAP, class Hash3 = HashFuncDJB>
class  BloomFilter
{
public:private:const size_t M = 5 * N;		// 【★】经研究得:布隆过滤器的长度最好是 开 要插入数据大小N 的 5倍bitSet<M> _bs;	    // 后面扩容,直接将bitSet的容器大小设置成M,方便后面扩容变动
};


reset() 删除 不能实现

在这里插入图片描述
删除了百度,则腾讯有一个位被reset()为0,则一个位为0,则直接判断腾讯不存在,即出现了误判的情况 。



布隆过滤器 码源实现

#pragma once
#include<set>
#include<string>using namespace std;
#include"bitset.h"struct HashFuncBKDR
{// BKDRsize_t operator()(const string& s){size_t hash = 0;for (auto ch : s){ch*=131;hash += ch;}return hash;}
};struct HashFuncAP
{// APsize_t operator()(const string& s){size_t hash = 0;for (size_t i=0;i<s.size();i++){if ((i & 1) == 0)	   // 偶数位字符{hash ^= ((hash << 7) ^ (s[i]) ^ (hash >> 3));}else       // 奇数位字符{hash ^= (~(hash << 11) ^ (s[i]++) ^ (hash >> 5));}}return hash;}};struct HashFuncDJB
{// DJBsize_t operator()(const string& s){size_t hash = 5381;for (auto ch : s){hash = hash * 33 ^ ch;}return hash;}
};template<size_t N,       // 要插入数据的个数class K= string,	    // 常用于布隆过滤器的key值是stringclass Hash1	= HashFuncBKDR,       // Hash1,Hash2,Hash3 通过不同的Hash哈希,分别映射到不同的三个位置class Hash2 = HashFuncAP, class Hash3 = HashFuncDJB>
class  BloomFilter
{
public:bool Set(const K& key){size_t hash1 = Hash1()(key) % M;size_t hash2 = Hash2()(key) % M;size_t hash3 = Hash3()(key) % M;_bs.set(hash1);_bs.set(hash2);_bs.set(hash3);}bool Test(const K& key){size_t hash1 = Hash1()(key) % M;if (_bs.test(hash1) == false)		// 只要判断出一个位不在,那就是(准确的)不在return false;size_t hash2 = Hash2()(key) % M;if (_bs.test(hash2) == false)		return false;size_t hash3 = Hash3()(key) % M;if (_bs.test(hash3) == false)		return false;return true;	// 存在误判(有可能判断到这3个位都是在的,但可能这3个位都冲突了)}// 布隆过滤器不好实现reset(),private:static const size_t M = 5 * N;		// 经研究得:布隆过滤器的长度最好是 开 要插入数据大小N 的 5倍	   // static是被放到静态区,不独属于对象,而是属于整个类bitSet<M> _bs;	    // 后面扩容,直接将bitSet的容器大小设置成M,方便后面扩容变动
};


在这里插入图片描述


在这里插入图片描述

为避免误判,先经过布隆过滤器判断:

  • 在,有可能昵称未注册过,位置被其他数据映射到,而发生误判
  • 不在,昵称没注册过 布隆过滤器的价值:(准确的,直接返回结果,提速,减少了数据库的访问压力)【以空间换时间】

误判的,再到数据库中进行验证 。



经典面试题

  1. 给两个文件,分别有100亿个query(查询),我们只有1G内存,如何找到两个文件交集?分别给出精确算法和近似算法
  • 近似算法:把一个文件放到布隆过滤器里面,另外一个文件 再去看,在就是交集,不在就不是交集
    【为什么说是近似的:因为布隆过滤器筛选出来的值,存在误判,】


  • 精确算法:

哈希切分:都放到内存(数据结构set)里面,去重,找交集

  1. 内存大小
    假设一个query 平均50byte,100亿个query占用多少空间?1G 约等于 10亿字节,那么一共需要500G。

  2. 将数据存储到一个一个文件(细分一千份)中(文件的存储,就是单纯的字节流的存储):
    依次每一个query,i = HashFunc(query) % 1000这个query就进入Ai文件中
    存放的是这个query本身,而HashFunc计算出来的hash值,只是用来得出query内容要放入的文件的编号

    A和B相同的query 一定会进入 编号相同的AiBi小文件只需要 遍历编号相同的文件 找交集 就可以了。
    平均切 找交集 O(N^2)(平均切:每个Ai文件都去遍历一遍Bi的每个文件),哈希切 找交集 O(N)


对于 切分的文件数量多少 的讨论

按理说,1G内存找切500份,这里切1000份,平均每份文件就是500M因为哈希切分是有的文件是冲突的有点多,有的文件大,有的文件小,避免出现因单个文件的内存存储的空间不够了,而存到下一个文件中,则不能做到哈希切分,找到对应标号的文件。



  1. 而后 将文件中的内容读到内存当中,运用内存当中的 哈希表unordered_set红黑树 进行处理,处理完了再把它清掉再读下一组文件:
    Ai的query放 哈希表set<string> seta,Bi的query放 哈希表set<string> setbsetasetb找交集即可

在这里插入图片描述


极端情况:某个文件冲突很多,导致Ai或者Bi太大了,比如超过1G,

那就 再走一层递归就可以了,再换一个哈希函数,再进行一次哈希切分
还是解决不了,某个文件还是特别特别的大,那就是 因为文件中存放的大部分 都是 相同的值
但 文件存入到 哈希表unordered_set中,有去重功能,重复的值不会再次插入

因此不会出现 文件中冲突的值很多是因为 重复的很多 而出现的 文件过大 的情况在存放进内存数据结构set中,就已经解决了这个问题
+ 重复出现的值很多的情况,set就已经解决了
+ 因此,只可能是因为其本身经过Hash函数后,哈希冲突还是很多 而造成的 。

query 插入set里面时,倘若抛异常,则代表query太多,且重复不多 。
在这里插入图片描述
解决办法:进行二次处理:换个哈希函数,对Ai和Bi文件再进行哈希切分 。



  1. 如何扩展BloomFilter使得它支持删除元素的操作
    引用计数:每个位置 改成 多个位的引用计数 就可以支持 。比如一个映射位置给8个bit位标记,但是这样空间消耗太大了。
    以前位图只需要标记0,1,只需要标记 或者 不在;而启用计数后,在位图中,最起码得 额外开八个bit位( 八个位能表示出255个数 ) (在原来位图的基础上开 )来进行映射 。

Counting Bloom Filter 的原理和实现



i=HashFunc(query)%100哈希切分出各Ai文件 + map<string, int>统计次数 + topK priority_queue小堆 :统计出topK的IP地址

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

分析:

  • 用map和set:100G大小的数据 内存占用太大了,内存搞不定。
  • 平均切分:这是个IP地址,平均切会*被分到不同的文件中。

哈希切分:

  1. 依次读取每个ipi = HashFunc(ip) % 100(一个文件开多大,取决于你设备的性能,最好是一个文件能放下 差不多两三百个IP地址 就好)
  2. 每个ip就 进入对应算出的Ai小文件:能进入同一个Ai小文件的,要么是相同的IP,要么是哈希冲突的IP 。
  3. 依次使用 map<string,int> countMap:统计每个文件ip的出现次数
    ( 如果map抛异常,则说明冲突很多,小文件很大 => 必须得换 哈希函数,二次切分处理;相同的文件ip就只是++int并不会对内存上开辟新的内存空间占用 )
  4. 然后 用 pair<string, int> maxIP来依次遍历每个文件找出 出现次数最大的文件ip ,比其大就进行更新,直到每个文件都遍历完了为止 。
  5. topK 就建立一个 小堆priority_queue< pair<string, int>, __?__ > minHeappriority_queue默认是大堆,因此此处若要实现 小堆 就需要自己实现 仿函数根据需求 “取pair<string, int>中的second 进行比较”


i=HashFunc(query)%100哈希切分成各Ai文件 + map<int, int> 逐一遍历哈希切分出的各Ai文件:统计出现的次数

重新看回【 海量面试题 】:给定100亿个整数,设计算法找到只出现一次的整数

原本采取的措施:

  • 开双位图:来记录出现的次数00 - 0次01 - 1次10 - 2次即以上
  • 哈希切分:这里的类型是 整型,直接用 整型 去 %取模 就好了

海量数据处理 问题的特征

  1. 数据量大,内存存不下
    如 哈希表unordered_map、红黑树 这样的数据结构
  2. 先考虑具有特点的数据结构能否解决?
    位图、堆、布隆过滤器(节省空间)
  3. 大事化小 思路
    文件指针,磁盘中的一个磁头来定位,真的效率太慢了
    哈希切分 [ 不能平均切分 ]:相同的值进入相同的文件
    找交集、统计次数
  4. 文件当中有很多数据,这个时候只是想找这个数据 单纯的在不在
    B树/B+树

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

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

相关文章

Static关键字的用法详解

Static关键字的用法详解 1、Static修饰内部类2、Static修饰方法3、Static修饰变量4、Static修饰代码块5、总结 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 在Java编程语言中&#xff0c;static是一个关键字&#xff0c;它可以用于多种上…

React+TS前台项目实战(二十三)-- 基于属性自定义数值显示组件Decimal封装

文章目录 前言Decimal组件1. 功能分析2. 代码详细注释3. 使用方式4. 效果展示 总结 前言 今天要封装的Decimal 组件&#xff0c;是通过传入的属性进行定制化显示数值&#xff0c;在渲染时&#xff0c;会根据不同的情况显示整数部分、小数部分和单位&#xff0c;支持自定义样式…

shell脚本awk中使用for循环

今天想使用shell脚本处理一ini文件下的ip地址&#xff0c;也就是INTRANET&#xff0c;前面的ip地址&#xff0c;折腾挺久。文件格式如下&#xff1a; 正确代码&#xff1a; grep -E INTRANET /home/aaaa/bbbb/hostinfo.ini | awk -F , {for(i1; i<NF; i) if($i~"INT…

全国现状建筑数据,选中范围即可查询下载,富含建筑物位置、层数、建筑物功能、名称地址等信息!

今天分享的是一个绘制范围即可下载范围内的建筑数据下载工具&#xff0c;内含高质量建筑数据数据源&#xff0c;助力场地建设规模一目了然。 数据可视化&#xff1a; 建筑物位置、层数、建筑轮廓地图可见&#xff0c;辅助分析。 数据字段&#xff1a; 建筑高度、层数、基地面…

2024年度最佳大型语言模型(LLMs)汇总大全

大型语言模型(LLMs)是人工智能文本处理的主要类型&#xff0c;也现在最流行的人工智能应用形态。ChatGPT是迄今为止最著名的使用LLM的工具&#xff0c;它由OpenAI的GPT模型的特别调整版本提供动力。但还有许多其他聊天机器人和文本生成器&#xff0c;包括从Google Bard和Anthro…

加速度传感器信号处理注意事项

1 传感器分类 对于压电式压力传感器而言&#xff0c;输出信号是最重要的选择标准之一。压电式压力传感器与电子电路相连&#xff0c;电子电路将传感器产生的电荷成比例转换为电压。 如果选用外部设备&#xff08;电荷放大器&#xff09;充当电子元件&#xff0c;则称其为电…

【毛发教程】使用 Maya、XGen 和虚幻引擎创建马尾辫发型

Malte Resenberger-Loosmann是国外一名首席艺术家&#xff0c;他负责指导整个艺术部门来制作独立游戏项目中的3D建模。在本文中&#xff0c;Loosmann展示了马尾辫发型背后的工作流程&#xff0c;分享了 Maya 和虚幻引擎中的场景设置&#xff0c;并解释了 GS CurveTools 如何帮助…

基于IIS的Windows系统Django项目本地部署

参考&#xff1a; 1. 基于Windows平台的Django本地部署和腾讯云服务器上部署&#xff08;1&#xff09;_如何在服务器上发布部署django程序 csdn-CSDN博客 2.Windows server iis部署Django详细操作 - Django中文 - 博客园 (cnblogs.com) 3.在IIS中部署pythonDjango项目时出…

Python: 分块读取文本文件

在处理大文件时&#xff0c;逐行或分块读取文件是很常见的需求。下面是几种常见的方法&#xff0c;用于在 Python 中分块读取文本文件&#xff1a; 1、问题背景 如何分块读取一个较大的文本文件&#xff0c;并提取出特定的信息&#xff1f; 问题描述: fopen(blank.txt,r) quot…

使用任意电脑通过内网穿透生成的公网地址远程SSH连接本地Windows电脑

文章目录 前言1. Windows安装SSH服务2. Windows本地连接测试3. Windows安装Cpolar工具4. 配置SSH公网地址5. 远程SSH 连接测试6. 固定SSH公网地址7. 固定SSH地址测试 前言 在当今的数字化转型时代&#xff0c;远程连接和管理计算机已成为日常工作中不可或缺的一部分。对于Wind…

微信小程序留言板1

wxml&#xff1a; <view class"view2"> <text class"test1">留言&#xff1a;</text><input type"text" class"input1" bindinput"ipt"/><button class"btn" bindtap"btn"…

spring mvc学习

第四章 Spring MVC 第一节 Spring MVC 简介 1. Spring MVC SpringMVC是一个Java 开源框架&#xff0c; 是Spring Framework生态中的一个独立模块&#xff0c;它基于 Spring 实现了Web MVC&#xff08;数据、业务与展现&#xff09;设计模式的请求驱动类型的轻量级Web框架&am…

「媒体邀约」全国巡演,多地推介会,如何做好媒体宣传

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 媒体宣传加速季&#xff0c;100万补贴享不停&#xff0c;一手媒体资源&#xff0c;全国100城线下落地执行。详情请联系胡老师。 我们在做多地活动的时候&#xff0c;比如演唱会&#xff…

【LeetCode】十一、滑动窗口:长度最小的子数组 + 定长子串的元音最大数目

文章目录 1、滑动窗口2、leetcode209&#xff1a;长度最小的子数组3、leetcode1456&#xff1a;定长子串中元音的最大数目 1、滑动窗口 如下&#xff0c;有一个数组&#xff0c;现三个元素为一组&#xff0c;求最大的和&#xff0c;自然可以while循环实现&#xff1a;i 、i1、…

数据结构(Java):迭代器遍历【底层源码解析】

1、引言 我们知道&#xff0c;对于List系列集合&#xff0c;添加的元素是有序、可重复、有索引的&#xff1b;而对于Set系列集合&#xff0c;添加的元素是无序、不重复、无索引的。 那么使用for循环通过下标来对Set系列集合进行遍历&#xff0c;那显然是不行的。 迭代器就可…

51单片机-让一个LED灯闪烁、流水灯(涉及:自定义单片机的延迟时间)

目录 设置单片机的延迟&#xff08;睡眠&#xff09;函数查看单片机的时钟频率设置系统频率、定时长度、指令集 完整代码生成HEX文件下载HEX文件到单片机流水灯代码 (自定义延迟时间) 设置单片机的延迟&#xff08;睡眠&#xff09;函数 查看单片机的时钟频率 检测前单片机必…

JVM的五大内存区域

JVM的五大内存区域 JVM内存区域最粗略的划分可以分为 堆 和 栈 &#xff0c;当然&#xff0c;按照虚拟机规范&#xff0c;可以划分为以下几个区域&#xff1a; JVM内存分为线程独享区和线程共享区&#xff0c; 其中 方法区 和 堆 是线程共享区&#xff0c; 虚拟机栈, 本地方法…

延边幼儿园1*3 OLED柔性屏翻页一体机安装项目

一、产品介绍 本次项目在吉林省延吉市延边幼儿园内&#xff0c;引入了先进的55寸1*3 OLED柔性屏翻页一体机。该设备集高清显示、灵活翻页、互动教学等功能于一体&#xff0c;专为现代幼儿教育环境设计&#xff0c;旨在通过科技手段提升教学质量&#xff0c;丰富教学手段&#x…

1.1.2数据结构的三要素

一.数据结构的三要素 数据结构这门课着重关注的是数据元素之间的关系&#xff0c;和对这些数据元素的操作&#xff0c;而不关心具体的数据项内容 。 1.逻辑结构 &#xff08;1&#xff09;集合结构 &#xff08;2&#xff09;线性结构 数据元素之间是一对一的关系。除了第一个…

MongoDB-社区版-本地安装

系统&#xff1a;win10 1. 下载server:Download MongoDB Community Server | MongoDB 我选的zip包 2. 下载shell&#xff1a;MongoDB Shell Download | MongoDB 我选的zip包 3. 启动server 4. 启动shell, 完成