【C++入门到精通】位图 | 位图的实现[ C++入门 ]

在这里插入图片描述

引言

在C++编程中,位图是一种常用的数据结构,用于高效地表示大量的布尔值。它通过使用一个二进制位来表示每个元素的存在与否,从而节省了大量的内存空间。现在,让我们考虑这样一个问题:给定一个包含40亿个数的数据集合,我们需要快速判断一个特定的数是否存在于其中。如何有效地解决这个问题呢?

传统的线性搜索算法需要遍历整个数据集合,时间复杂度较高,无法满足实时性和高效性的要求。而位图算法则提供了一种更加优雅和高效的解决方案。通过将每个数映射到位图中的相应位置上,我们可以利用位运算来快速判断一个数是否存在

通过深入理解位图算法的原理和实现,我们将能够在处理大规模数据集合时提供高效的查找功能。无论是在数据处理、搜索引擎还是其他需要频繁进行数值查找的场景中,位图算法都将发挥重要的作用。让我们开始探索吧!坐稳扶好咱们要开车了😍

一、位图的概念

1. 官方文档

| ===============================
| 🔴 位图的官方文档介绍
| ===============================
在这里插入图片描述

2. 基本概念

位图是一种数据结构,用于高效地表示大量的布尔值。它通过使用一个二进制位来表示每个元素的存在与否,从而节省了大量的内存空间

具体来说,位图由一组二进制位(0或1)组成,其中每个位代表一个元素的存在状态。如果该位为1,则表示对应的元素存在;如果该位为0,则表示对应的元素不存在。通过这种方式,位图可以将大量的元素用较少的内存空间表示出来,从而提高了数据的处理效率。

在C++中,位图通常使用一个字符数组来表示。假设我们需要表示 n n n 个元素的存在状态,那么我们可以使用一个长度为 ( n / 8 + 1 ) (n/8+1) (n/8+1) 的整数数组来表示位图。其中,每个整数表示8个元素的存在状态。例如,如果第 i i i 个元素存在,则我们可以将第 i i i 个二进制位设置为1,并将其所在的整数存储在位图数组的第 i / 8 i/8 i/8 个位置上。比如:

在这里插入图片描述
通过这种方式,我们可以快速地进行元素的插入、删除和查找操作。在插入一个元素时,我们只需要将相应的二进制位设置为1即可;在删除一个元素时,我们只需要将相应的二进制位设置为0即可;在查找一个元素时,我们只需要检查相应的二进制位是否为1即可。后面我会详细介绍。

总之,位图是一种简单而高效的数据结构,可以用于处理大规模的布尔值集合。在C++编程中,我们可以使用位运算和整数数组来实现位图,并通过位图算法来提高数据的处理效率。

二、位图的实现

1. 插入

位图的插入操作是将一个元素的存在状态设置为1,使其在位图中被标记为存在

  1. 计算索引:首先,需要确定要插入的元素在位图中对应的索引位置。通常情况下,位图使用字符数组来表示,每个整数可以表示8个元素的存在状态。因此,我们可以通过将元素的值除以8来计算它在整数数组中的索引。

    int idx = n / 8;
    
  2. 计算偏移量:接下来,需要确定要插入的元素在位图中对应的二进制位的偏移量。偏移量是指元素在整数中的二进制位的位置。我们可以通过将元素的值模8来计算偏移量。

    int pos = n % 8;
    
  3. 设置二进制位:最后,通过使用位运算和按位或操作,将对应的二进制位设置为1,即将元素插入位图。

    bitmap[idx] |= (1 << pos);
    

    这里,(1 << pos) 表示将1左移pos位,得到一个只有第pos位为1的二进制数。然后,使用按位或操作符|=将这个二进制数与位图中对应索引的整数进行按位或运算,将对应的二进制位设置为1。

2. 删除

位图的删除操作是将一个元素的存在状态设置为0,使其在位图中被标记为不存在

  1. 计算索引:首先,需要确定要操作的元素在位图中对应的索引位置。由于每个char变量可以表示8个元素的存在状态,因此我们可以通过将元素的值除以8来计算它在char数组中的索引。

    int idx = n / 8;
    
  2. 计算偏移量:接下来,需要确定要操作的元素在位图中对应的二进制位的偏移量。由于每个char变量可以表示8个元素的存在状态,我们可以通过将元素的值模8来计算偏移量。

    int pos = n % 8;
    
  3. 清除二进制位:最后,通过使用位运算和按位与操作,将对应的二进制位设置为0,即将元素从位图中删除。

    bitmap[idx] &= ~(1 << pos);
    

这里,~(1 << pos) 表示将1左移pos位,得到一个只有第pos位为0的二进制数,然后使用按位与操作符&=将这个二进制数与位图中对应索引的整数进行按位与运算,将对应的二进制位设置为0。

3. 查找

在位图中进行查找操作时,我们可以通过检查对应的二进制位来确定元素是否存在

  1. 计算索引:首先,需要确定要查找的元素在位图中对应的索引位置。由于每个char变量可以表示8个元素的存在状态,因此我们可以通过将元素的值除以8来计算它在char数组中的索引。

    int idx = n / 8;
    
  2. 计算偏移量:接下来,需要确定要查找的元素在位图中对应的二进制位的偏移量。由于每个char变量可以表示8个元素的存在状态,我们可以通过将元素的值模8来计算偏移量。

    int pos = n % 8;
    
  3. 检查二进制位:使用按位与操作符&将对应的二进制位提取出来,并检查其值是否为1。

    int bit = bitmap[idx] & (1 << pos);
    

    这里,(1 << pos) 表示将1左移pos位,得到一个只有第pos位为1的二进制数。然后,使用按位与操作符&将这个二进制数与位图中对应索引的char变量进行按位与运算,提取出对应的二进制位。

  4. 判断结果:根据上一步得到的结果,判断元素是否存在于位图中。

    • 如果结果为0,则表示元素不存在于位图中。
    • 如果结果不为0,则表示元素存在于位图中。

C++模拟实现

  1. 类定义:定义了一个名为bitset的类,并使用模板参数size_t N指定位图的大小。

    template<size_t N>
    class bitset
    {
    public:
    	...
    private:
    	vector<char> _bits;
    };
    
  2. 构造函数:在构造函数中,首先通过将位图大小除以8并加1来计算需要分配的char数组的大小,然后使用vector容器创建一个大小为该值的char数组,并将所有元素初始化为0。

    bitset()
    {
        _bits.resize(N/8 + 1, 0);
    }
    
  3. set函数:set函数用于设置位图中的元素。它首先计算元素在位图中对应的索引和偏移量,然后使用按位或操作符|将对应的二进制位设置为1。

    void set(size_t x)
    {
        size_t i = x / 8;
        size_t j = x % 8;
    
        _bits[i] |= (1 << j);
    }
    
  4. reset函数:reset函数用于重置位图中的元素。它首先计算元素在位图中对应的索引和偏移量,然后使用按位与非操作符~和按位与操作符&将对应的二进制位设置为0。

    void reset(size_t x)
    {
        size_t i = x / 8;
        size_t j = x % 8;
    
        _bits[i] &= ~(1 << j);
    }
    
  5. test函数:test函数用于测试位图中的元素是否存在。它首先计算元素在位图中对应的索引和偏移量,然后使用按位与操作符&将对应的二进制位提取出来,并返回其值。

    bool test(size_t x)
    {
        size_t i = x / 8;
        size_t j = x % 8;
    
        return _bits[i] & (1 << j);
    }
    
  6. 私有成员变量:在类定义中,还定义了一个名为_bits的私有成员变量,用于存储位图中的数据。该变量是一个char类型的vector容器,大小为位图大小除以8并加1,所有元素初始化为0。

    private:
    	vector<char> _bits;
    

🔴完整代码

#include <vector>

template<size_t N>
class bitset
{
public:
    // 构造函数
    bitset()
    {
        // 计算需要分配的char数组的大小,并使用vector容器创建一个大小为该值的char数组
        // 将所有元素初始化为0
        _bits.resize(N/8 + 1, 0);
    }

    // 设置位图中的元素
    void set(size_t x)
    {
        // 计算元素在位图中对应的索引和偏移量
        size_t i = x / 8;
        size_t j = x % 8;

        // 使用按位或操作符|将对应的二进制位设置为1
        _bits[i] |= (1 << j);
    }

    // 重置位图中的元素
    void reset(size_t x)
    {
        // 计算元素在位图中对应的索引和偏移量
        size_t i = x / 8;
        size_t j = x % 8;

        // 使用按位与非操作符~和按位与操作符&将对应的二进制位设置为0
        _bits[i] &= ~(1 << j);
    }

    // 测试位图中的元素是否存在
    bool test(size_t x)
    {
        // 计算元素在位图中对应的索引和偏移量
        size_t i = x / 8;
        size_t j = x % 8;

        // 使用按位与操作符&将对应的二进制位提取出来,并返回其值
        return _bits[i] & (1 << j);
    }

private:
    // 存储位图数据的私有成员变量
    std::vector<char> _bits;
};

总结

位图是一种用于表示和操作大量二进制位的数据结构。它通过使用一个固定长度的数组来存储位的状态,每个位可以表示某种信息的存在与否。位图常用于解决需要高效存储和操作大量布尔类型数据的问题。在C++中,可以使用类似上述的位图类来模拟实现位图功能,实现插入、删除和查找等操作。位图的优点是占用空间小、操作高效,但受限于位数范围。

感谢您对博主文章的关注与支持!另外,我计划在未来的更新中持续探讨与本文相关的内容,会为您带来更多关于C++以及编程技术问题的深入解析、应用案例和趣味玩法等。请继续关注博主的更新,不要错过任何精彩内容!

再次感谢您的支持和关注。期待与您建立更紧密的互动,共同探索C++、算法和编程的奥秘。祝您生活愉快,排便顺畅!

  • 78
    点赞
  • 75
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 69
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 69
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Yawesh

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

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

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

打赏作者

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

抵扣说明:

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

余额充值