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

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

引言

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

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

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

一、位图的概念

1. 官方文档

| ===============================

| 🔴 位图的官方文档介绍

| ===============================


2. 基本概念

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

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

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

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

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

二、位图的实现

1. 插入

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

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

int idx = n / 8;

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

int pos = n % 8;

设置二进制位:最后,通过使用位运算和按位或操作,将对应的二进制位设置为1,即将元素插入位图。

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

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

2. 删除

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

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

int idx = n / 8;


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

int pos = n % 8;

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

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

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

3. 查找

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

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

int idx = n / 8;

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

int pos = n % 8;

检查二进制位:使用按位与操作符&将对应的二进制位提取出来,并检查其值是否为1。

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

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

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

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

C++模拟实现

  1. 类定义:定义了一个名为bitset的类,并使用模板参数size_t N指定位图的大小。
template<size_t N>
class bitset
{
public:
  ...
private:
  vector<char> _bits;
};

构造函数:在构造函数中,首先通过将位图大小除以8并加1来计算需要分配的char数组的大小,然后使用vector容器创建一个大小为该值的char数组,并将所有元素初始化为0。

bitset()
{
    _bits.resize(N/8 + 1, 0);
}

set函数:set函数用于设置位图中的元素。它首先计算元素在位图中对应的索引和偏移量,然后使用按位或操作符|将对应的二进制位设置为1。

void set(size_t x)
{
    size_t i = x / 8;
    size_t j = x % 8;

    _bits[i] |= (1 << j);
}

reset函数:reset函数用于重置位图中的元素。它首先计算元素在位图中对应的索引和偏移量,然后使用按位与非操作符~和按位与操作符&将对应的二进制位设置为0。

void reset(size_t x)
{
    size_t i = x / 8;
    size_t j = x % 8;

    _bits[i] &= ~(1 << j);
}

test函数:test函数用于测试位图中的元素是否存在。它首先计算元素在位图中对应的索引和偏移量,然后使用按位与操作符&将对应的二进制位提取出来,并返回其值。

bool test(size_t x)
{
    size_t i = x / 8;
    size_t j = x % 8;

    return _bits[i] & (1 << j);
}

私有成员变量:在类定义中,还定义了一个名为_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++、算法和编程的奥秘。祝您生活愉快,排便顺畅!


目录
相关文章
|
4天前
|
C++ 存储 编译器
|
4天前
|
存储 算法 C语言
【C++入门到精通】C++的IO流(输入输出流) [ C++入门 ]
【C++入门到精通】C++的IO流(输入输出流) [ C++入门 ]
21 0
|
4天前
|
设计模式 安全 算法
【C++入门到精通】特殊类的设计 | 单例模式 [ C++入门 ]
【C++入门到精通】特殊类的设计 | 单例模式 [ C++入门 ]
18 0
|
3天前
|
编译器 C++
C++入门(命名空间)
C++入门(命名空间)
|
4天前
|
C++ 编译器 程序员
C++ 从零基础到入门(3)—— 函数基础知识
C++ 从零基础到入门(3)—— 函数基础知识
|
4天前
|
C++ 存储
C++从零基础到入门(2)—— (if、switch、for、while语句)
C++从零基础到入门(2)—— (if、switch、for、while语句)
C++从零基础到入门(2)—— (if、switch、for、while语句)
|
4天前
|
算法 Go 数据库
数据结构/C++:位图 & 布隆过滤器
数据结构/C++:位图 & 布隆过滤器
12 0
|
4天前
|
编译器 C语言 C++
C++入门基础-2
C++入门基础
12 3
|
4天前
|
C语言 C++
C++入门基础-1
C++入门基础
18 1