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日

相关文章

  • 8个简单部分开启Java语言学习之路 附java学习书单

    8个简单部分开启Java语言学习之路 如果你想要学习Java语言,但是不知道从何入手,在这里,我们将为你提供一份简单易懂的攻略,分8个步骤带你开启Java语言学习之路。 1. 安装Java开发工具 Java学习的第一步是安装Java开发工具,目前比较流行的Java开发工具有多种,例如Eclipse、Intellij IDEA、NetBeans等。本攻略以In…

    数据结构 2023年5月17日
    00
  • Lua教程(七):数据结构详解

    Lua教程(七):数据结构详解 Lua 中的数据结构广泛应用于各种计算机程序中。本文将详细介绍 Lua 中的数组、列表、栈、队列、集合和字典等数据结构的使用以及相关的函数。 数组 数组是存储在连续内存位置上的相同数据类型的元素集合。Lua 中的数组索引默认从 1 开始。下面是一些常用的 Lua 数组函数: table.concat(arr[, sep[, i…

    数据结构 2023年5月17日
    00
  • 在matlab中创建类似字典的数据结构方式

    当需要使用类似字典的数据结构时,Matlab中可以使用结构体来实现。结构体是一种有序的数据集合,每个元素都可以包含不同类型的数据(如字符串、数值等),并通过指定一个名称来唯一地标识该元素。 创建一个空结构体 使用struct函数可以创建一个空的结构体,可以使用下面的代码: st = struct; 添加键值对 可以将键值对添加到结构体中,可以使用下面的代码向…

    数据结构 2023年5月17日
    00
  • C语言数据结构二叉树先序、中序、后序及层次四种遍历

    C语言数据结构二叉树四种遍历 什么是二叉树 二叉树是一种非常重要的数据结构,在计算机科学中具有广泛的应用。它由节点和边组成,每个节点最多有两个子节点。二叉树有许多种遍历方法,可以用来查找节点、在树中插入新节点、删除节点等操作。 二叉树遍历 二叉树遍历是指对二叉树的节点进行访问,有4种遍历方式: 先序遍历(Preorder Traversal) 中序遍历(In…

    数据结构 2023年5月17日
    00
  • C语言数据结构之平衡二叉树(AVL树)实现方法示例

    C语言数据结构之平衡二叉树(AVL树)实现方法示例 介绍 AVL树是一种自平衡二叉搜索树,它保证了所有节点的左右子树高度差不超过1,从而提高了查找、插入和删除操作的效率。本篇文章将介绍如何使用C语言实现AVL树,并提供两个例子以说明实现方法。 实现方法 结构体定义 首先,定义AVL树节点的结构体,包括该节点存储的值、该节点的高度、该节点的左右子树指针。 ty…

    数据结构 2023年5月17日
    00
  • Python 实现数据结构-堆栈和队列的操作方法

    Python 实现数据结构-堆栈和队列的操作方法 在Python中,我们可以使用列表(List)数据类型来实现堆栈和队列的操作。 堆栈(Stack)的操作方法 堆栈数据结构可以理解为一种后进先出的数据存储方式,也就是说最后放入堆栈的元素最先被取出。下面介绍一下堆栈的操作方法。 创建一个堆栈 我们可以通过创建一个空的列表来实现一个堆栈。代码如下: stack …

    数据结构 2023年5月17日
    00
  • C++数据结构与算法之判断一个链表是否为回文结构的方法

    当我们遇到判断一个链表是否为回文结构的问题时,可以考虑使用如下的方法: 遍历链表,将链表节点的值存储到一个数组或者栈中。 遍历链表,将链表节点的值与前面存储的值进行比较,如果全部相同,则证明链表为回文结构。 下面是详细的代码实现和示例说明: 实现 首先,我们需要定义一个链表节点的结构体,包括节点值和指向下一个节点的指针: struct ListNode { …

    数据结构 2023年5月17日
    00
  • Python中的函数式编程:不可变的数据结构

    Python是一门支持函数式编程的语言。相比于传统的命令式编程,函数式编程更加强调数据的不可变性。本文将介绍如何在Python中使用不可变的数据结构实现函数式编程。 什么是不可变的数据结构? 不可变数据结构是指一旦创建就无法改变的数据结构。在Python中,元组(tuple)是一个典型的不可变数据结构。以下是一个创建元组的示例代码: a_tuple = (1…

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