C++ 数据结构之布隆过滤器

C++ 数据结构之布隆过滤器

简介

布隆过滤器是一种用于快速判断一个元素是否存在于一个集合中的数据结构。它的空间效率和查询效率都比较高,在某些场景下,它可以代替传统的哈希表。

原理

布隆过滤器的基本原理是:将一个元素映射为多个位数组中的位置。在插入元素时,将这些位置上的值设置为1;在查询元素时,如果这些位置上的值都为1,则认为元素存在于集合中;否则认为元素不存在。(由于哈希函数的不可逆性,可能会出现把不同元素映射到同一位置的情况,因此判断元素不存在是有误差的,但判断元素存在则是准确的)。

为了使误判率尽可能小,布隆过滤器需要用到一个较大的位数组,以及多个不同的哈希函数。一般情况下,哈希函数使用 MurmurHash 或 xxHash 等快速哈希函数即可。

实现

下面介绍一个简单的布隆过滤器的实现。

代码如下:

#include <vector>
#include <cstdlib>
#include <ctime>

class BloomFilter {
public:
    BloomFilter(int n, double p): bit_array_(n), k_(std::log(2) * n / p) {
        srand(time(nullptr));
        for (int i = 0; i < k_; i++) {
            int random_seed = rand();
            hash_seeds_.push_back(random_seed);
        }
    }

    void Add(const std::string& str) {
        for (int i = 0; i < k_; i++) {
            int position = Hash(str, hash_seeds_[i]) % bit_array_.size();
            bit_array_[position] = true;
        }
    }

    bool Query(const std::string& str) const {
        for (int i = 0; i < k_; i++) {
            int position = Hash(str, hash_seeds_[i]) % bit_array_.size();
            if (!bit_array_[position]) {
                return false;
            }
        }
        return true;
    }

private:
    std::vector<bool> bit_array_;
    std::vector<int> hash_seeds_;
    int k_;

    int Hash(const std::string& str, int seed) const {
        unsigned int hash = seed;
        for (int i = 0; i < str.size(); i++) {
            hash = hash * 131 + str[i];
        }
        return hash;
    }
};

这段代码中,我们使用了一个 std::vector<bool> 类型的数组作为位数组,以及一个 std::vector<int> 类型的数组作为哈希种子。

在构造函数中,我们需要指定期望布隆过滤器的大小 n 和误判率 p。根据布隆过滤器的原理,一般情况下需要满足 k = ln(2) * n / p,其中 k 为哈希函数的个数。

随机生成 k 个哈希种子,用来生成 k 个哈希函数。

在插入元素时,通过 k 个哈希函数将元素映射到位数组中。将这些位置上的值设置为 1。

在查询元素时,同样使用 k 个哈希函数将元素映射到位数组中。如果所有位置上的值都为 1,则认为元素存在于集合中;否则认为元素不存在。

示例

下面给出两个使用布隆过滤器的示例。

示例1:URL去重

在爬虫程序中,我们需要对爬取到的每个URL进行去重操作。如果使用一个传统的哈希表来进行去重,需要使用大量的内存来存储这些URL,而且查询速度会较慢。布隆过滤器可以帮助我们在较小的空间和较快的查询速度之间取得平衡。

int main() {
    BloomFilter filter(1000000, 0.001);
    std::string url1 = "https://www.baidu.com";
    std::string url2 = "https://www.baidu.com";
    filter.Add(url1);
    if (filter.Query(url2)) {
        std::cout << "URL already exists." << std::endl;
    } else {
        std::cout << "URL does not exist." << std::endl;
    }
    return 0;
}

在上面的示例中,我们创建了一个布隆过滤器,指定了 1000000 的大小,以及 0.001 的误判率。然后向过滤器中插入了一个名字相同的 URL,并且查询了另一个名字相同的 URL。

示例2:IP黑名单过滤

在网络应用中,我们需要对一些IP地址进行黑名单过滤,防止这些IP地址发起攻击。布隆过滤器可以帮助我们在较小的内存和较快的查询速度之间取得平衡。

int main() {
    BloomFilter filter(1000000, 0.001);
    std::string ip1 = "192.168.0.1";
    std::string ip2 = "192.168.0.2";
    filter.Add(ip1);
    if (filter.Query(ip2)) {
        std::cout << "IP is in blacklist." << std::endl;
    } else {
        std::cout << "IP is not in blacklist." << std::endl;
    }
    return 0;
}

在上面的示例中,我们创建了一个布隆过滤器,指定了 1000000 的大小,以及 0.001 的误判率。然后向过滤器中插入了一个 IP 地址,并且查询了另一个 IP 地址,看它是否在黑名单中。

总结

布隆过滤器是一种空间效率和查询效率都比较高的数据结构,常用于集合判重、黑名单过滤等场景中。使用布隆过滤器需要注意一些参数的设置,以及哈希函数的选择。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++ 数据结构之布隆过滤器 - Python技术站

(0)
上一篇 2023年5月17日
下一篇 2023年5月17日

相关文章

  • C语言线性表之双链表详解

    C语言线性表之双链表详解 前言 本教程将详细介绍C语言中双链表的实现方法以及相关操作,适合有一定C语言基础的读者。 双链表定义 双链表是一种常见的数据结构,与单链表不同,双链表中每个节点不仅有指向后续节点的指针,还有指向前续节点的指针,即“双向链表”。 双链表的节点结构体可以定义如下: typedef struct double_node{ int data…

    数据结构 2023年5月17日
    00
  • js处理层级数据结构的方法小结

    “JS处理层级数据结构的方法小结”是一篇讲解JavaScript如何处理嵌套数据结构的文章。在现代的web应用中,嵌套结构是非常常见的,比如JSON数据、树形数据等。以下是对该话题的详细讲解: 1. 嵌套数据结构的概念 指的是包含嵌套关系的数据类型,如数组、对象、树形结构、XML文档等。这些类型之间有着固定层级关系,包含多个层次的数据。嵌套数据结构的处理,往…

    数据结构 2023年5月17日
    00
  • C语言数据结构之栈简单操作

    C语言数据结构之栈简单操作 什么是栈? 栈(Stack)是一种线性数据结构,它具有“后进先出”(Last-In-First-Out)的特性。栈顶是栈的一端,另一端称为栈底。每次只能从栈顶插入数据(入栈)或者从栈顶取出数据(出栈)。 栈的简单操作 栈的简单操作包括: 初始化栈 判断栈是否为空 判断栈是否已满 入栈操作 出栈操作 获取栈顶元素 栈的初始化 栈的初…

    数据结构 2023年5月16日
    00
  • Java集合和数据结构排序实例详解

    Java集合和数据结构排序实例详解 作为Java程序员,集合和数据结构是我们经常会用到的工具,其中排序是其中非常重要的一环。本文将为大家详细介绍Java中集合和数据结构排序的实例。 Java集合排序 在Java中,集合排序通常使用Collections工具类来完成。Collections提供了多种排序算法,包括插入排序、选择排序、归并排序等等。例如,下面的示…

    数据结构 2023年5月17日
    00
  • Javascript中扁平化数据结构与JSON树形结构转换详解

    一、扁平化数据结构 扁平化数据结构是指将一个JSON树形结构数据转换为一个扁平化的对象数组,通常用于在数据操作中进行遍历和检索,方便数据的处理和展示。 例如,有一个JSON树形结构数据如下: { "name": "中国", "children": [ { "name": &quo…

    数据结构 2023年5月17日
    00
  • C++ 数据结构之kmp算法中的求Next()函数的算法

    C++ 数据结构之kmp算法中的求Next()函数的算法 什么是KMP算法和Next()函数 KMP算法(Knuth-Morris-Pratt算法)是一种字符串匹配算法,能够解决的问题是,在一个文本串S中查找一个模式串P是否出现并且返回第一次出现的位置。而Next()函数则是在KMP算法中使用的一个关键的子函数,用于计算模式串P中每个前缀的最长相同真前缀和后…

    数据结构 2023年5月17日
    00
  • java数据结构实现顺序表示例

    如果想要实现一种数据结构,我们首先需要考虑它的存储结构。对于顺序存储结构,Java中的数组是一个很好的选择。下面就为大家分享关于Java数据结构实现顺序表示例的完整攻略,帮助读者更好地理解该数据结构的实现方式。 1. 定义一个顺序表数组 首先,我们需要定义一个数组类型的顺序表。这个顺序表可以使用泛型来表示各种类型的数据: public class MyArr…

    数据结构 2023年5月17日
    00
  • Java数据结构之栈与队列实例详解

    Java数据结构之栈与队列实例详解攻略 简介 栈和队列是常见的数据结构,在Java中也有对应的实现方式。本文将介绍栈和队列的概念、常见实现方式、应用场景和两个示例。 栈 概念 栈是一种具有后进先出(Last In First Out)特性的数据结构。栈可以使用数组或链表实现。 常见实现方式 基于数组的栈实现 使用数组作为底层存储结构实现栈时,需要注意栈顶指针…

    数据结构 2023年5月17日
    00
合作推广
合作推广
分享本页
返回顶部