c++位图之bitset

bitset简单来说就是一个bit数组,和java里面的bitmap类似。

这次简单分析一下bitset以及它的应用。


目录

一.c++中bitset的使用

二.bitset的简单实现

三.bitset的应用


一.c++中bitset的使用

就用一段代码来说明,使用很简单。

#include <bitset>
#include <iostream>

int main()
{
    std::bitset<10>bit("0000000001");                   /* 可用字符串初始化,尖括号指定bit位数 */
    std::cout << bit << std::endl;
    bit[1] = 1;                                         /* 和数组使用方式一样 */
    std::cout << bit << std::endl;
    std::cout << "bit[1]:" << bit[1] << std::endl;
    std::cout << "test:" << bit.test(1) << std::endl;   /* 类似bit[1] */
    std::cout << "count:" << bit.count() << std::endl;  /* 计算使用过的bit位*/
    std::cout << "size:" << bit.size() << std::endl;
    std::cout << "any:" << bit.any() << std::endl;      /* 测试是否有bit被修改过 */
    std::cout << "none:" << bit.none() << std::endl;    /* 测试是否所有bit没有被修改过*/
    std::cout << "all:" << bit.all() << std::endl;      /* 测试所有bit是否被修改过 */ 
    std::cout << "to_string:" << bit.to_string() << std::endl;  /* 转成string类型 */
    std::cout << "to_ulong:" << bit.to_ulong() << std::endl;    /* 转成ulong类型 */
    std::cout << "to_ullong:" << bit.to_ullong() << std::endl;  /* 转成ullong类型*/
}




二.bitset的简单实现

源自编程珠玑的第一章第二题,让我们通过&,|,>>来实现bit数组。

 * 定义一个整型的数组,每一位
 * 代表一个bit*/

#include <iostream>

#define BitTegrSize (sizeof(int)*8)
#define N 10000000                   /* 1000W数据 */

int main()
{
    unsigned int array[1+N/BitTegrSize];      /* 开多大的数组 */
    unsigned int a[2] = {0, 0};               /* 测试 */
    std::cout << sizeof(int) << std::endl;
    a[33>>5] |= (1 << ((33&0x1f)-1));
    std::cout << a[1] << std::endl;
    std::cout << (a[0] | 1) << std::endl;
    int b = 0;
    std::cout << (b | 1) << std::endl;
}

代码中假设是用unsigned int 型数组来实现的(实际上内部是用什么类型实现的不一定,这里只是举例子,vs早期有用unsigned int来实现)

a[33>>5] |= (1 << ((33&0x1f)-1));     将指定位设置为1,这里是设置a[33]

重点说说这个:33>>5等价于33/32,unsigned int 是32位,含义是定位到该bit所在的元素中,|= 与运算就是修改某一位为1,

(33&0x1f) 是通过&取余运算,且只能针对2^n的数取余

解释一下这个0x1f是16进制的31,转化为2进制就是11111111,为什么取余32等于&31呢?

这个其实很好理解,比如x%y,余数最大就是y-1,所以在x转化为2进制代码中的数值我只关心它的起始的那几位即可 ,至于是几位就和y有关系了,比如

y等于16,那么最大余数是15,我就只关心起始5位,例如:x为10101000101010100001101,我就只关心红色几位数值即可,它们就是余数,&运算只是

把它们提取出来。(注意前面说了值针对2^n,原因是二进制呗!

同理清除为1的指定位也就简单了。


三.bitset的应用

两个例子

1.某区有7位电话号码若干(千万级别),要求对其排序,占用内存要求在1MB左右。

大概算一下,8位电话号码也就是0000000-9999999,数值一共不到1千万吧,用unsigned即可。

那么加载进内存越为4*10000000字节,约等于40MB,如果我们用排序只能用归并排序了,至少也40次了吧,先不说次数多少,就磁盘IO来说就慢的不行了。

此时可以考虑bitset了,既然电话号码是连续的且不重复的,我们可以用bitset的bit下标来表示电话号码,比如1234567,就是bit[1234567]。那么好办了,

首先计算一下bitset需要的大概是40MB/32,也就是1MB左右,复合情况,我们可以直接遍历一遍,存在的号码S我们设置b[S]位为1,不存在则为0。

那么输出排序直接遍历bitset即可。节省空间且速度快^_^。


2. 2.5亿个整数中找出不重复的整数的个数,内存空间不足以容纳这2.5亿个整数。

这次用两个位表示一个数,00表示未出现过,01表示出现立了1次,11表示出现重复了。

遍历即可


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

夏天的技术博客

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

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

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

打赏作者

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

抵扣说明:

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

余额充值