接下来要换一个手机号,不知道怎么挑选,就想,要是能有一个素数手机号就好了,于是虽然有这类工具,但还是想写个程序做这件事;
如果想给出一个区间内的素数表,常用筛法,维基百科上给出了这种方法的描述:
给出要筛数值的范围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; }
后记:这个代码写起来很有趣,以至于都不在意手机号的事情了。