zoukankan      html  css  js  c++  java
  • 一种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;
    }

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

  • 相关阅读:
    linux-Windows文件上传Linux
    linux-ifconfig 查看没有IP
    springBoot 发布war/jar包到tomcat(idea)
    linux-常用命令
    (转)JVM各种内存溢出是否产生dump
    数据库缓存的几种方式
    使用jprofiler分析dump文件一个实例
    Hibernate之一级缓存和二级缓存
    最佳实践 缓存穿透,瞬间并发,缓存雪崩的解决方法
    缓存与数据库一致性之三:缓存穿透、缓存雪崩、key重建方案
  • 原文地址:https://www.cnblogs.com/intervention/p/4031828.html
Copyright © 2011-2022 走看看