C++位图 | bitmap

引入

再说C++位图之前,我们先看一个经典的面试题。

给40亿个不重复的且无序的 unsigned int 整数,然后给出一个整数,判断这个数是否在这40亿个数中?

我们简单分析一下题目:

  1. 快速判断。在编程中提到效率,一般有一招, “空间换时间”。具体实现就是借助数组的查询时间复杂度为常数级别( O(1) )。
  2. 判断是否存在。 只有两个状态,存在和不存在,正好对应二进制的0和1

那我们就可以这样设计了。

用数组的下标索引值表示数字,如果有则对应位设置为 1,否则为 0。

那我们就创建一个40亿大小的数组吧。数组存放什么类型的数据呢?bool?char?int?short?

都不太好,就算只占一个字节的bool类型,也有8bit,而我们只需1bit表示是否存在。即存在为1,不存在为0。

这样存在大量空间的浪费。设想一下,40亿个数据将占用多少内存,又有多少内存是可以节约下来的?至少7/8.

那我们怎么办?

位图

C++中的位图通常指的是使用位运算来表示和处理数据的数据结构。

取位

上面我们说的bool类型有8位,我们可以借助简单的运算来实现一种映射,将每八位数据对应一个bool类型的8位bit。

类似先定位段,再定位在段中的位置。

在这里插入图片描述

要存放一个数据 value,要找到它对应bool数组的元素的位置索引,然后在找到它对应元素的多少位。

定位存放索引value / (8 * sizeof(value_type))

定位bit位值value % (8 * sizeof(value_type))

上面如果是bool,则8 * sizeof(value_type)取8;如果是 int ,就是4*8=32位。

设置位

借助位运算 可以很简单的实现。

设置为 1: b[value / 8] |= (1 << (value % 8))

判断是否存在: b[value / 8] & (1 << (value % 8))

很好理解,不过我们还是举个例子。

bool 数组b,  存放 value , 值为 2121 / 8 = 2, 故 value 存放在数组的索引为2位上,即 b[2]
21 % 8 = 5, 故 valeu 存放在b[2]上的索引为 5 的位上。
设置存在
bool[2] |= (1<<5);

使用

现在解决最初给出的题目

给40亿个不重复的且无序的 unsigned int 整数,然后给出一个整数,判断这个数是否在这40亿个数中?

代码

#include <iostream>
#include <vector>
using namespace std;

#define SIZET_LEN (sizeof(size_t) * 8)

class BitMap
{
public:
    BitMap(size_t _size)
    {
        this->size = _size;
        ibits.resize(_size / SIZET_LEN, 0);
    }

    void Set(size_t index)
    {
        if (index <= size)
            ibits[index / SIZET_LEN] |= (ONE << (index % SIZET_LEN));
    }

    bool Exist(size_t index)
    {
        if(index <= size)
            return ibits[index / SIZET_LEN] & (ONE << (index % SIZET_LEN));
        
        return false;
    }

    void Reset(size_t index)
    {
        if(index <= size)
            ibits[index / SIZET_LEN] &= ~(ONE << (index % SIZET_LEN));
    }

protected:
    std::vector<size_t> ibits;
    size_t size;
    static size_t ONE;
};

size_t BitMap::ONE = 1;

void test1()
{
    BitMap b(unsigned(-1)); 
    b.Set(2);
    b.Set(479);
    b.Set(5678765);
    b.Set(999999999);
    b.Set(0xFFFFFFFF);

    cout << b.Exist(478) << endl; 
    cout << b.Exist(479) << endl; 
    cout << b.Exist(5678765) << endl;
    cout << b.Exist(999999999) << endl;
    cout << b.Exist(0xFFFFFFFF) << endl;


    cout << "---------\n";
    cout << b.Exist(5678765) << endl;
    b.Reset(5678765);
    cout << b.Exist(5678765) << endl;
}

int main()
{
    test1();
    return 0;
}
这是一个用于C++ MFC开发Bitmap图片操作类,在文件中叫CBitmapEx,可用于放大,缩小,翻转,过渡和其他有用的功能,有兴趣的朋友可以下载看看。 部分public method: // // void Create(long width, long height); // void Create(CBitmapEx& bitmapEx); // void Load(LPTSTR lpszBitmapFile); // void Save(LPTSTR lpszBitmapFile); // void Scale(long horizontalPercent=100, long verticalPercent=100); // void Rotate(long degrees=0, _PIXEL bgColor=_RGB(0,0,0)); // void FlipHorizontal(); // void FlipVertical(); // void MirrorLeft(); // void MirrorRight(); // void MirrorTop(); // void MirrorBottom(); // void Clear(_PIXEL clearColor=_RGB(0,0,0)); // void Negative(); // void Grayscale(); // void Sepia(long depth=34); // void Emboss(); // void Engrave(); // void Pixelize(long size=4); // void Draw(HDC hDC); // void Draw(long dstX, long dstY, long width, long height, // CBitmapEx& bitmapEx, long srcX, long srcY); // void Draw(long dstX, long dstY, long width, long height, // CBitmapEx& bitmapEx, long srcX, long srcY, long alpha); // void Draw(long dstX, long dstY, long dstWidth, long dstHeight, // CBitmapEx& bitmapEx, long srcX, long srcY, long srcWidth, long srcHeight); // void Draw(long dstX, long dstY, long dstWidth, long dstHeight, CBitmapEx& bitmapEx, // long srcX, long srcY, long srcWidth, long srcHeight, long alpha); // void DrawTransparent(long dstX, long dstY, long width, long height, // CBitmapEx& bitmapEx, long srcX, long srcY, _PIXEL transparentColor=_RGB(0,0,0)); // void DrawTransparent(long dstX, long dstY, long width, long height, // CBitmapEx& bitmapEx, long srcX, long srcY, long alpha, // _PIXEL transparentColor=_RGB(0,0,0)); // void DrawTransparent(long dstX, long dstY, long dstWidth, long dstHeight, // CBitmapEx& bitmapEx, long srcX, long srcY, long srcWidth, long srcHeight, // _PIXEL transparentColor=_RGB(0,0,0)); // void DrawTransparent(long dstX, long dstY, long dstWidth, long dstHeight, // CBitmapEx& bitmapEx, long srcX, long srcY, long srcWidth, long srcHeight, // long alpha, _PIXEL transparentColor=_RGB(0,0,0)); // LPBI
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值