一种bitset类的简单实现

接下来要换一个手机号,不知道怎么挑选,就想,要是能有一个素数手机号就好了,于是虽然有这类工具,但还是想写个程序做这件事;

如果想给出一个区间内的素数表,常用筛法,维基百科上给出了这种方法的描述:

  给出要筛数值的范围n,找出sqrt(n)以内的素数p1,p2,...,pk
  先用2去筛,即把2留下,把2的倍数剔除掉;
  再用下一个素数,也就是3筛,把3留下,把3的倍数剔除掉;
  接下去用下一个素数5筛,把5留下,把5的倍数剔除掉;
  不断重复下去......

首先要有一个能够容纳18,100,000,000(从0到180号段的最大值)的数组
如果我们使用char[]来存储,那么需要18G的内存,但是因为每一个数组元素只需要1个bit表示"是/否",所以想到了采用位元组
虽然说vector 和bitset都可以满足需求,但是那样就没有什么意思了,想自己实现一个

首先遇到的问题就是这个类的operator[],返回值必须是一个左值bool&
但是因为这个类的内部实现是用了位压缩,一个字节存储了8个bool值,并不可能返回其中某一个bit的引用
经过思考之后,得到了一种实现:
1、给类添加一个bool类型的成员变量val_,当operator[]的时候,检查byte_array_里面对应bit的值并赋给val_,返回的是对val_的引用
2、内部有变量index_记录下operator[]所访问的数组的下标;
3、每次调用operator[]之前,调用函数finish_last_operation_(),通过val_和index_,把上次的结果写到真正的数组里去;
参考代码如下:

#include <malloc.h>
#include <string.h>
#include <stdexcept>

typedef long long int64;

class my_bitset
{
public:
    my_bitset(int64 size);
    ~my_bitset();
    bool& operator[](int64 idx);
    void clear();
    void set_all();
    my_bitset& operator=(const my_bitset &mbs) = delete;
    my_bitset(const my_bitset &mbs) = delete;

private:
    void finish_last_operation_();

private:
    bool val_;
    unsigned char * byte_array_;
    int64 index_;
    int64 size_;
};

my_bitset::my_bitset(int64 size) : size_(size)
{
    int64 block_size = (size_ >> 3) + 1;
    this->byte_array_ = (unsigned char *)malloc(block_size * sizeof(unsigned char));
    val_ = 0;
    index_ = -1;
}

my_bitset::~my_bitset()
{
    free(this->byte_array_);
}

bool& my_bitset::operator[](int64 idx) //下标操作
{
    finish_last_operation_();
    int64 arr_idx = idx >> 3;
    int64 in_idx = idx & 0x07;
    this->index_ = idx;
    if (idx >= this->size_)
        throw std::runtime_error("Query Out of Range");
    unsigned char temp = byte_array_[arr_idx];
    if (temp & (0x1 << in_idx))
        this->val_ = true;
    else
        this->val_ = false;
    return this->val_;
}

void my_bitset::finish_last_operation_() //完成上一次的操作
{
    if (this->index_ == -1)
        return;
    int64 arr_idx = this->index_ >> 3;
    int in_idx = this->index_ & 0x7;
    if (this->val_)
    {
        this->byte_array_[arr_idx] |= 0x1 << in_idx;
    }
    else
    {
        this->byte_array_[arr_idx] &= ~(0x1 << in_idx);
    }
}

void my_bitset::clear()
{
    int64 block_size = (this->size_ >> 3) + 1;
    memset(this->byte_array_, 0, block_size * sizeof(unsigned char));
    this->val_ = 0;
    this->index_ = -1;
}

void my_bitset::set_all()
{
    int64 block_size = (this->size_ >> 3) + 1;
    memset(this->byte_array_, -1, block_size * sizeof(unsigned char));
    this->val_ = 0;
    this->index_ = -1;
}

后记:这个代码写起来很有趣,以至于都不在意手机号的事情了。

posted @ 2014-07-11 18:39  intervention  阅读(615)  评论(1编辑  收藏  举报