bitset类的实现

C++: 模拟实现类bitset C++: 模拟实现类bitset标签: C++ bitset 位运算by 小威威1.bitset简介bitset能实现对数字的位的操作,同时也能通过类似于数组的下标来访问各个位的数值,以执行相应的操作。模拟bitset就是用一个普通的数组来存储数据以达到模拟的目的。先声明一下,本篇文章并不是讲述标准库中bitset这个类的用法,而是去讲述如何实现一个模拟bitset的类。众所周知,int类型在64 阅读详情

问题:实现一个bitmap类(为避免与stl中的bitset重名),用于位图。

测试用例:

BitMap bm(20);
bm[3] = 1;
bm[5] = 0;
bool b = bm[12];

其本质上是用内存中的一位来表示某种意义。

难点在于,使用int或者unsigned int类型保存多位bool变量(也就是0或者1)后,怎么重载下标操作符。

如果不使用下标而是使用函数,例如bm.set(3);或者bm.reset(12);一般是很简单的,只需要重载[]即可。

使用下标操作符的难点在于:c++不支持bit引用。

但是就是要求使用下标操作(项目中你可以这么做,但是面试的时候,面试官就要求使用下标),how?


这里需要使用一种设计模式:代理模式。


先看代码:

#include <iostream>
#include <cassert>

/****************************************
 * 20130506 微软实习生面试时悲剧的题目
 * 当时根本没想到代理模式
 * 至于代理模式,以前也仅仅是听说过而已
*****************************************/
using namespace std;

/*****************************************
 * BitMap bm(20);
 * bm[9]=1;//set bit
 * bm[1]=0;//clear
*****************************************/
class BitMap
{
    typedef unsigned int UINT;

public:
    BitMap(size_t bitlen=0):m_len(bitlen)
    {
        nUINT=m_len/DATALEN+(m_len%DATALEN==0?0:1);
        m_data = new UINT[nUINT]();
    }
    ~BitMap()
    {
        delete[] m_data;
    }
    void set(size_t index)
    {
        assert(0<=index&&index<m_len);
        *(m_data+index/DATALEN) = *(m_data+index/DATALEN) | (1<<(index%DATALEN));
    }
    void reset(size_t index)
    {
        assert(0<=index&&index<m_len);
        *(m_data+index/DATALEN) = *(m_data+index/DATALEN)&(~(1<<(index%DATALEN)));
    }
    bool test(size_t index)const
    {
        assert(0<=index&&index<m_len);
        return *(m_data+index/DATALEN) & ( 1<<(index%DATALEN));
    }
    void flip()///~all bits
    {
        for(unsigned int i=0;i<nUINT;i++)
            *(m_data+i) ^= (~0);
    }

/****  代理模式 ****/
    class proxy
    {
    public:
        proxy(BitMap &refbm, size_t index):
            rbm(refbm),index(index)
            {
            }

        proxy & operator= (bool val)
        {
            if(val)
                rbm.set(index);
            else
                rbm.reset(index);
            return *this;
        }

        proxy & operator= (const proxy &rhs)
        {
            if(rhs.rbm.test(rhs.index))
                rbm.set(index);
            else
                rbm.reset(index);
            return *this;
        }
        operator bool()
        {
            return rbm.test(index);
        }

    private:
        BitMap &rbm;
        size_t index;

    };

    proxy operator[](size_t index)
    {
        return proxy(*this,index);
    }

    const proxy operator[] (size_t index) const
    {
        return proxy(const_cast<BitMap &>(*this), index);
    }

private:
    UINT *m_data;///实际保存bit的存储区
    size_t m_len;///位的长度,支持可变长度的位,bitset不支持。
    size_t nUINT;///实际使用的UINT的个数

    const static int DATALEN = 32;///每个UINT可以保存的bit个数

    friend ostream& operator<< (ostream& out,BitMap &bm);///用于输出,便于调试
};

ostream& operator<< (ostream& out,BitMap &bm)
{
    for(int i=bm.m_len-1;i>=0;i--)
        out<<bm.test(i);
    return out;
}


void testcase()
{
    BitMap b(40);
    cout<<b<<endl;;
    b.set(2);
    b.set(3);
    cout<<b<<endl;
    b.reset(2);
    cout<<b<<endl;

    b.flip();
    cout<<b<<endl;

    cout<<"ttt"<<endl;
    b[1]=0;
    cout<<b<<endl;
    b[1]=1;
    cout<<b[0]<<endl;
}


int main()
{
    testcase();
    return 0;
}


前面的set、reset、flip等函数的实现就是位运算,不需要多说。

关键在这里:

b[1]=0;

首先,b[1]将调用下标操作符,

    proxy operator[](size_t index)
    {
        return proxy(*this,index);
    }

这里返回的是一个proxy对象。proxy怎么构造的呢?2个参数:BitMap引用和index。这2个参数足以定位到一个具体的bit!也就是说,一个proxy对象对应一个bit。

然后将一个bool值赋值给这个对象,将调用proxy的赋值操作符:

        proxy & operator= (bool val)
        {
            if(val)
                rbm.set(index);
            else
                rbm.reset(index);
            return *this;
        }

这样就修改了BitMap对象的某一位。


还有一处需要说明的地方:

        operator bool()
        {
            return rbm.test(index);
        }

这里定义了类型转换,可以将一个proxy对象转换为一个bool变量。读取的时候,例如bool  b=bm[2];将调用这个函数。


这样,对外看来,使用下标访问的就是BitMap对象中的某一位,可以进行读或者写的操作。

很巧妙的设计。


/*********************************************分****割****线***************************************************************/

关于代理模式:

代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

直接看这些定义,感觉理解起来很不方便。

有了这个例子,体会得深的多了。

有人说:

“设计模式就是编程思想,很多新手觉得好像都看懂了但不会用,因为编程思想还没达到那个层次!

这个要靠点点滴滴的积累,当你积累了10W行有效代码,再回过头去看设计模式,自然会有豁然开朗的感觉

框架要用,“不要重复造轮子”,但是要关注框架的实现原理”


深有体会!



Python 实现类似C++的bitset类 C++ 的 bitset 和 Java 的 BitSet 在位操作中都十分方便和强大,能够极大地节省内存,提高操作效率。遗憾的是,Python 竟然没有提供类似的类或模块。不过利用 Python 本身的强大能力,实现一个类似的 bitset 类,十分容易,下面我们就来纯手工打造一个属于自己的 Python 的 BitSet 类。本文抛砖引玉,在实际应用中,需要对异常进行处理,例如输入的位置不合法等 阅读详情

相关推荐

9、Java中的BitSet类与集合框架入门

本文详细介绍了Java中的BitSet类及其常用方法,以及Java集合框架的基础知识和核心接口,包括Collection、List、Set和Map。同时,文章还探讨了集合框架的实现类、算法、性能特点以及高级应用场景,帮助开发者更好地理解和使用Java集合框架进行高效的数据操作。

ggg99的专栏 127

BitSet的实现原理

1.BitSet介绍 Bitset是Java中的一种数据结构。Bitset中主要存储的是二进制位,做的也都是位运算,每一位只用来存储0,1值,主要用于对数据的标记。 Bitset的基本原理是,用1位来表示一个数据是否出现过,0为没有出现过,1表示出现过。使用的时候可以根据某一个位是否为0表示此数是否出现过。JDK中的BitSet集合对是布隆过滤器中经常使用的数据结构Bitmap的相对简单的实现...

forever-and-ever的博客 2万+

bitset:紧凑的位集实现

描述 该程序包包含固定大小的内存中位集的有效实现。 BitSet支持的操作是: 得到 设置,设置全部 清除,清除全部 反转,全部反转 还有一种解析方法,该方法允许从零和一的字符串构造BitSet。 例子 package main import ( "fmt" "github.com/lazybeaver/bitset" ) func main() { bs := bitset.New(4) bs.Set(0) bs.Set(2) bs.InvertAll() if bs.Get(1) { bs.Clear(3) } fmt.Println(bs.String()) } 基准测试 索引范围检查和获取位置和掩码的函数调用是当前实现中最昂贵的部分。 $ go test -bench=. PASS BenchmarkGet 500000000 6.

【C++从入门到踹门】第十九篇:bitset(位图)的使用与实现

常规的想法是将40亿个数存入数组中,快速排序然后采用二分法查找,时间复杂度O(NlogN).或者是将一堆数存入unordered_set容器中,使用find进行查找,时间复杂度为O(N)。但是内存空间存不下这么多的数字:40亿≈232=22 * 2^10 * 2^10 * 2^10=4 * 1024 * 1024 * 1024 = 4G每个整数占4字节,所以40亿个整数占用16G字节的空间而一台32位机的内存地址有32位,每个地址指向1字节(8bits)的数据,其内存地址空间的大小只有2^32=4G字节的空

qq_43041053的博客 5570

c++ bitset实现

自己实现的bitset数据结构,在vs2005下编译通过。有测试成素。

从零到飞:在Ubuntu 22.04上为你的无人机搭建PX4-Autopilot开发环境

本文详细指导在Ubuntu 22.04上搭建PX4-Autopilot开发环境,涵盖系统依赖安装、源码获取、编译目标选择及Gazebo仿真测试。通过优化构建过程和调试技巧,帮助开发者快速为无人机部署稳定的飞控系统,实现从仿真到实机的平滑过渡。

weixin_26878995的博客 490

bitset(C++实现)

位图实际上就是一个指定比特位个数的连续内存空间,所以可以用STL内置的容器vector管理,除此之外,理论上任何类型都可以作为元素的类型,只不过为了容易理解,它的每个元素的类型被设定为char。

Man9o 2190

TL3562/3568内核驱动移植实战:解决无锡沐创N500L-AM4网口异常问题

本文详细介绍了在TL3562/3568平台上移植无锡沐创N500L-AM4网卡驱动的实战经验,重点解决了第四个网口通讯异常问题。通过升级驱动版本至rnpgbe-0.2.3,生成关键头文件并正确配置内核,最终实现四个网口稳定工作。文章还提供了性能优化建议和避坑指南,为类似硬件驱动移植项目提供参考。

weixin_28273593的博客 180

自己实现的Bitset类

自己用C++实现的Bitset类, 功能参考STL的bitset类, 由于VS2005不支持模板的分离编译, 所以都实现在了一个名为Bitset.h的头文件里. 肯定有一些bug, 请各位高手帮忙抓虫. 抛砖引玉, 博大家一晒. 1: #ifndef BIT_SET_H 2: #define BIT_SET_H 3: //Readme 4: //本程序实现了一个类似std:

imgen的专栏 1491

SBP依赖计算中的蝴蝶效应:一个Prefab修改如何触发全量重建?

本文深入探讨了Unity中SBP(Scriptable Build Pipeline)依赖计算的蝴蝶效应,解析了Prefab修改如何触发全量重建的机制。通过分析Asset与Object的层级关系、依赖计算的三种维度及CacheEntry系统,揭示了全量重建的根本原因,并提供了依赖可视化工具开发、优化策略与最佳实践,帮助开发者提升构建效率。

weixin_29015051的博客 445

用 ABAP RAP + XCO 把 Excel 导入业务对象:从弹窗 Action 到 EML 落库与附件清理的完整实践

摘要:本文介绍了在SAP RAP框架下实现Excel批量导入功能的完整方案。通过XCO库的XLSX模块解析Excel文件,结合RAP的行为定义和Fiori Elements界面集成,构建了一个支持试运行、数据校验和自动合并的业务导入功能。方案采用RAP标准范式,包括Action参数设计、EML事务处理、附件管理以及异常消息反馈,实现了从文件上传到数据落库的端到端流程,既保证了系统稳定性,又提升了业务用户体验。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 278

smo算法c语言源代码,Python 实现类似C++的bitset类

C++ 的 bitset 和 Java 的 BitSet 在位操作中都十分方便和强大,能够极大地节省内存,提高操作效率。遗憾的是,Python 竟然没有提供类似的类或模块。不过利用 Python 本身的强大能力,实现一个类似的 bitset 类,十分容易,下面我们就来纯手工打造一个属于自己的 Python 的 BitSet 类。本文抛砖引玉,在实际应用中,需要对异常进行处理,例如输入的位置不合法等...

weixin_29981095的博客 252

10|Git Diff 与增量代码识别:本次到底改了哪些代码?

本文介绍 Git Diff 和增量代码识别,帮助你理解精准测试如何先找到本次真正变化的代码。测试开发工程师。Java 后端开发工程师。质量平台 / DevOps 平台建设者。想了解精准测试落地方法的技术负责人。

专注 AI 精准测试平台实战落地,分享从代码 Diff 到回归决策的完整工程闭环。主张“先建数据链路,再上 AI 智能”,让测试从“靠经验”走向“基于风险”。 160

Java BitSet类解析:高效位向量实现

Java的BitSet类实现了一个动态增长的位向量,通过long数组高效存储位数据。核心设计包括:1. 每个long存储64位,使用位移运算快速定位;2. 自动扩容机制确保存储空间;3. 提供set/flip/clear等原子位操作方法,以及and/or等集合运算;4. 支持与字节数组/缓冲区的相互转换。该类采用小端字节序,通过wordsInUse字段优化存储空间,但不保证线程安全。典型应用场景包括高效处理大量布尔值、位标志集合等。

lifallen的博客 1095

SOME/IP协议详解「4.1·经典AutoSAR下的SOME/IP架构」

SOME/IP协议详解「4.1·经典AutoSAR下的SOME/IP架构」 点击返回雪云飞星的SOME/IP协议详解「总目录」 SOME/IP协议详解「4.1·经典AutoSAR下的SOME/IP架构」1 CP的SOME/IP架构概览2 业务报文通信流3 服务发现通信和控制流 1 CP的SOME/IP架构概览 2 业务报文通信流 3 服务发现通信和控制流 点击返回雪云飞星的SOME/IP协议详解「总目录」 ...

雪云飞星的博客 6069

我用 Python 把 Claude 变成了 “代码审查员“:每次提交前 AI 先 Review,Bug 漏网率降了 80%

这是成败的关键。我们需要给 Claude 立规矩,让它像一个严格的架构师那样思考。你是一名资深的首席软件架构师和安全专家。请审查以下 Git Diff 代码变更。你的任务是:1. **安全性检查**:寻找 SQL 注入、XSS、硬编码密钥、敏感信息泄露等。2. **潜在 Bug**:空指针、资源未关闭、竞态条件、逻辑死循环。3. **代码质量**:命名规范、冗余代码、可读性差、缺乏注释。4. **性能优化**:不必要的数据库查询、低效算法。

BUG猿的博客 145

2022-04-24:位集 Bitset 是一种能以紧凑形式存储位的数据结构。 请你实现 Bitset 类。 Bitset(int size) 用 size 个位初始化 Bitset ,所有位都是 0

2022-04-24:位集 Bitset 是一种能以紧凑形式存储位的数据结构。 请你实现 Bitset 类。 Bitset(int size) 用 size 个位初始化 Bitset ,所有位都是 0 。 void fix(int idx) 将下标为 idx 的位上的值更新为 1 。如果值已经是 1 ,则不会发生任何改变。 void unfix(int idx) 将下标为 idx 的位上的值更新为 0 。如果值已经是 0 ,则不会发生任何改变。 void flip() 翻转 Bitset 中每一位上的值。换

福大大架构师每日一题 2万+

【QGIS】软件下载安装及GIS4WRF插件使用

【QGIS】软件下载安装及GIS4WRF插件使用

WW、forever的博客 1800

一种bitset类的简单实现

接下来要换一个手机号,不知道怎么挑选,就想,要是能有一个素数手机号就好了,于是虽然有这类工具,但还是想写个程序做这件事; 如果想给出一个区间内的素数表,常用筛法,维基百科上给出了这种方法的描述: 给出要筛数值的范围n,找出sqrt(n)以内的素数p1,p2,...,pk 先用2去筛,即把2留下,把2的倍数剔除掉; 再用下一个素数,也就是3筛,把3留下,把3的倍数剔除掉; ...

weixin_30861459的博客 202

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

了解BitSet类并实现素数筛选--Eratosthenes筛选法

今天看到了java集合当中的一个位集BitSet,先说一下BitSet,BitSet类用于存放一个位序列,如果需要高效的存储位序列可以使用位集,因为位集将位包装在了字节里面,所以使用位集要比使用Boolean对象的ArrayList更为高效 BitSet取值为true和false,在API里面有以下几个方法

liangzi321321的博客 725

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

C# 仿java按位操作的BitSet实现

测试代码 using System.Diagnostics; namespace Test { class Program { static void Main(string[] args) { BitSet bitset = new BitSet(8); bitset.Set(4, true); Debug.WriteLine(bitset.ToString());

forward_huan的博客 984

【STL】bitset的模拟实现

我们知道,一个整型有32个比特位,但我们传来的位图肯定不可能是32的倍数的,所以我们就需要在结束完/32以后就加1,往后多开一个32个位的空间,将多余的空间放到下一个位图中。打印函数就是先打印前n-1个数值的比特位的值,再打印最后一个整数的32个比特位中前面被设置的值。在构造位图时,我们需要根据所给位数N,创建一个N位的位图,并且将该位图中的所有位都初始化为0。size成员函数用于获取位图中可以容纳的位的个数,即直接计算参数模板中的位的个数即可。2、再检查最后一个整数的前N%32个比特位是否为全1。

m0_70088010的博客 287

C++STL(十) :bitset的模拟实现

我们只需遍历每一个整数,若这些整数全部都为0,则说明位图中没有位被设置过。一个整型有32个比特位,因此N个位的位图就需要用到N/32个整型,但是实际我们所需的整型个数是N/32+1,因为所给非类型模板参数N的值可能并不是32的整数倍。位图中是否全部位都没有被设置,实际上就是位图中有位被设置的反面,因此none成员函数直接调用any成员函数,然后将返回值取反后再进行返回。获取位图中被设置的位的个数,也就是统计位图中1的个数,我们只需要依次统计每个整数二进制中1的个数,然后将其相加即可得到位图中1的个数。

weixin_74006549的博客 1052

bitset(位图)模拟实现

一个整形有32个比特位,因此N个位的位图就需要用到N/32个整形,但实际上我们所需的整型个数是N/32+1,因为所给非整型模板参数N的值可能并不是32的整数倍.位图中是否全部位都没有被设置,实际上就是位图中有位没设置了,因此none成员函数直接调用any成员函数,然后将返回值取反后在进行返回即可.获取位图中被设置的位的个数,也就是统计位图中1的个数,我们只需要依次统计每个整数二进制中1的个数,然后相加即可得到位图中1的个数.size成员函数用于获取位图中可以容纳的位的个数.reset成员函数用于清空位.

m0_70657810的博客 988

c++手写的bitset

支持stl bitset 类似的api。

qq_34179431的博客 698
上一篇: Linux常用命令总结
下一篇: 找出数组中的缺失数据和重复数据
quickSort
博客等级 码龄15年 51粉丝 57原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值