位图和布隆过滤器,以及哈希切割思想

目录

1、前言

2、位图

位图的模拟实现

位图的应用场景

3、布隆过滤器

 布隆过滤器的模拟实现


1、前言

在好多面试题中,会有海量数据量的场景,那么遇到这些问题该怎么去入手,今天来看看位图和布隆过滤器以及哈希切割的思想,本篇文章仅仅为个人学习过程中的记录,如果有错误,请各位友友们指出,

2、位图

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

1. 遍历,时间复杂度O(N)

2. 排序(O(NlogN)),利用二分查找: logN

3. 位图解决

数据是否在给定的整形数据中,结果是在或者不在,刚好是两种状态,那么可以使用一个二进制比特位来代表数据是否存在的信息,如果二进制比特位为1,代表存在,为0代表不存在。

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

位图的模拟实现

//bitset.hpp
#pragma once

#include <iostream>
#include <vector>

using namespace std;

namespace ltx {
	
	
	class bitset {

	public:
		bitset(size_t size) :_v(size), _size(0) {}

		// 将which比特位置1
		void set(size_t which) {
			size_t i = which / 8;
			size_t j = which % 8;
			if (!((_v[i] >> j) & 1)) {
				_v[i] |= (1 << j);
				_size++;
			}
				
		}
		// 将which比特位置0
		void reset(size_t which) {
			size_t i = which / 8;
			size_t j = which % 8;
			if (!((_v[i] >> j) & 1)) {
				_v[i] &= ~(1 << j);
				_size--;
			}
		}
		// 检测位图中which是否为1
		bool test(size_t which) {
			size_t i = which / 8;
			size_t j = which % 8;
			return (_v[i] >> j) & 1;
		}
		size_t size()const { return _size; }

	private:
		vector<char> _v;
		size_t _size;
	};
	
}

位图的应用场景

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

2. 排序 + 去重

3. 求两个集合的交集、并集等

4. 操作系统中磁盘块标记

3、布隆过滤器

布隆过滤器是由布隆(Burton Howard Bloom)在1970年提出的  一种紧凑型的、比较巧妙的概率型数据结构,特点是高效地插入和查询,可以用来告诉你 “某样东西一定不存在或者可能存在”,它是用多个哈希函数,将一个数据映射到位图结构中。此种方式不仅可以提升查询效率,也可以节省大量的内存空间。

他使用的是哈希的思想,但是可能会发生冲突,不存在是精确的,但是存在是不精确的。

 布隆过滤器的模拟实现

//BloomFilter.hpp
#pragma once

#include "bitset.hpp"

namespace ltx {

    struct KeyToInt1 {
        size_t operator()(const string& s) {
            // BKDR
            size_t value = 0;
            for (auto ch : s)
            {
                value *= 31;
                value += ch;
            }
            return value;
        }
    };
    struct KeyToInt2 {
        size_t operator()(const string& s) {
            size_t hash = 5381;
            for (auto ch : s)
            {
                hash += (hash << 5) + ch;
            }
            return hash;
        }
    };
    struct KeyToInt3 {
        size_t operator()(const string& s) {
            size_t hash = 0;
            for (long 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;
        }
    };

    // 假设布隆过滤器中元素类型为K,每个元素对应3个哈希函数
    template<class K, class KToInt1 = KeyToInt1, class KToInt2 = KeyToInt2, class KToInt3 = KeyToInt3>
    class BloomFilter
    {
    public:
        BloomFilter(size_t size)  // 布隆过滤器中元素个数
            : _bmp(5 * size), _size(size)
        {}

        // 插入数据
        bool Insert(const K& key) {
            KToInt1 k1;
            KToInt2 k2;
            KToInt3 k3;
            size_t i1 = k1(key) % (5 * _size);
            size_t i2 = k2(key) % (5 * _size);
            size_t i3 = k3(key) % (5 * _size);
            _bmp.set(i1);
            _bmp.set(i2);
            _bmp.set(i3);
            return true;
        }
        // 检测在不在
        bool IsInBloomFilter(const K& key) {
            KToInt1 k1;
            KToInt2 k2;
            KToInt3 k3;
            size_t i1 = k1(key) % (5 * _size);
            size_t i2 = k2(key) % (5 * _size);
            size_t i3 = k3(key) % (5 * _size);
            if (!_bmp.test(i1))
                return false;
            else if (!_bmp.test(i2))
                return false;
            else if (!_bmp.test(i3))
                return false;
            return true;
        }
            // 位图不支持删除
    private:
        ltx::bitset _bmp;
        size_t _size;   // 实际元素的个数
    };
}

海量数据巨量的题目,和解决(这里的解决完全是我自己个人的想法,如果有错误,请各位大佬指出来)

求两个文件的交集:精确算法和近似算法:

        给两个文件,分别有100亿个query,我们只有1G内存,如何找到两个文件交集?分别给出精确算法和近似算法。如何扩展BloomFilter使得它支持删除元素的操作

        答:不管使用精确算法还是近似算法,首先都要对这100亿个query进行哈希切割,

近似算法:

        直接使用BloomFilter进行两个文件切割后的哈希切块query进行统计求交集

精确算法:

        对文件进行哈希切割后,可以使用哈希表对两个文件的分割块求交集

对BoolFilter进行扩展,让其支持删除元素的操作:

        可以使用可以将key的模型改成key_value的模型,记录每个比特位被标记的次数,删除的时候这个比特位的次数-1,如果设计好的算法,减少哈希碰撞的几率,使用两位比特位就可以解决删除的操作

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

        答:对位图进行变形或者封装,这样每个数据,就可以得到两个可操作比特位,也就可以表示四种状态,分别可以表示为:

        00表示未出现过

        01表示出现过一次

        10表示出现过两次

        11表示出现过两次以上

然后再对这些数据进行统计处理,最后就可以找出出现次数不超过两次的整数了

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

        答:可以使用两个位图,分别映射统计两个文件中出现的整数,最后对比两张位图就可以得出两个文件的交集

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

对位图进行变形或者封装,这样每个数据,就可以得到两个可操作比特位,也就可以表示四种状态,分别可以表示为:

        00表示未出现过

        01表示出现过一次

        10表示出现过两次以上

然后再对这些数据进行统计处理,最后就可以找出出现过一次的整数了

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

先对这个日志文件进行哈希切割,然后使用哈希表对一个切割后的IP地址进行统计出现的次数,

使用建小堆的方式,统计top k

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孟婆的cappucino

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值