BitMap算法

所谓的BitMap就是用一个bit位来标记某个元素所对应的value,由于BitMap使用了bit位来存储数据,因此可以大大节省存储空间。

基本思想:

我们用一个简单的例子来详细介绍BitMap算法的原理。假设我们要对0-7内的5个元素(4,7,2,5,3)进行排序(这里假设元素没有重复)。我们可以使用BitMap算法达到排序目的。要表示8个数,我们需要8位,即1个byte。

  1.首先我们开辟一个字节的空间,将这些空间的所有的位都设置为0

  2.然后遍历这5个元素,第一个元素是4,因此我们把第五位的值设置为1

  3.然后再处理剩下的四个元素,最终1个字节的状态如下图

  4.现在我们遍历一次bytes区域,把值为1的byte的位置输出(2,3,4,5,7),这样便达到了排序的目的

  从上面的例子我们可以看出,BitMap算法的思想还是比较简单的,关键的问题是如何确定10进制的数到2进制的映射图

MAP映射:

假设需要排序或则查找的数的总数N=100000000,BitMap中1bit代表一个数字,1个int = 4Bytes = 4*8bit = 32 bit, 那么N个数需要N/32 int空间。所以我们需要申请内存空间的大小为int a[1 + N/32],其中:a[0]在内存中占32为可以对应十进制数0-31,依次类推:

  a[0]-----------------------------> 0-31

  a[1]------------------------------> 32-63

  a[2]-------------------------------> 64-95

  a[3]--------------------------------> 96-127

  ......................................................

  那么十进制数如何转换为对应的bit位,下面介绍用位移将十进制数转换为对应的bit位:

  1.求十进制数在对应数组a中的下标

  十进制数0-31,对应在数组a[0]中,32-63对应在数组a[1]中,64-95对应在数组a[2]中………,使用数学归纳分析得出结论:对于一个十进制数n,其在数组a中的下标为:a[n/32]

  2.求出十进制数在对应数a[i]中的值

  例如十进制数1在a[0]的值为1,十进制数31在a[0]中值为31,十进制数32在a[1]中值为0。 在十进制0-31就对应0-31,而32-63则对应也是0-31,即给定一个数n可以通过模32求得在对应数组a[i]中的值。

  3.位移

  对于一个十进制数n,对应在数组a[n/32][n%32]中,但数组a毕竟不是一个二维数组,我们通过移位操作实现置1

  a[n/32] |= 1 << n % 32
  移位操作:
  a[n>>5] |= 1 << (n & 0x1F)

  n & 0x1F 保留n的后五位, 相当于 n % 32 求十进制数在数组a[i]中的值

代码实现

#include<iostream>
#include<vector>
using namespace std;

int N = 10000000;
int a[10000000/32 + 1] = {0};
class BitMap {

    public:
        void addValue(int n);
        bool exits(int n);
        void display(int row);
};

//设置所在的bit位为1
void BitMap::addValue(int n){
    //row = n / 32 求十进制数在数组a中的下标
    int row = n >> 5;
    //相当于 n % 32 求十进制数在数组a[i]中的下标
    a[row] |= 1 << (n & 0x1F);
}

// 判断所在的bit为是否为1
bool BitMap::exits(int n){
    int row = n >> 5;
    return (a[row] & ( 1 << (n & 0x1F))) == 1;
}

void BitMap::display(int row){
        cout<<"BitMap位图展示"<<endl;
        for(int i=0;i<row;i++)
        {
            cout<<"a["<<i<<"] ";
            int temp = a[i];
            for(int j=0;j<32;j++)
            {
                if(temp & 1)
                {
                    if (j == 31)
                        cout<<1<<endl;
                    else
                        cout<<"1, ";
                }
                else
                {
                    if (j == 31)
                        cout<<0<<endl;
                    else
                        cout<<"0, ";
                }
                temp >>= 1;
            }
        cout<<endl;
        }
}

int main(){
    int num[] = {1,5,30,32,64,56,159,120,21,17,35,45};
    BitMap map;
    for(int i=0;i < sizeof(num)/sizeof(num[0]);i++){
        map.addValue(num[i]);
    }

    int temp = 120;
    if(map.exits(temp)){
        cout<<"temp:"<<temp<<"has already exists"<<endl;
    }
    map.display(5);
    return 0;
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
雪花算法是一种生成分布式唯一ID的算法,可以保证生成的ID在分布式系统中的唯一性。而Bitmap算法则是一种数据压缩算法,如何将这两个算法结合起来呢? 实际上,在雪花算法中,每个ID都是由时间戳、机器ID和序列号组成的。因此,我们可以将机器ID和序列号使用Bitmap算法进行压缩,从而减小ID的存储空间。 具体来说,我们可以使用两个Bitmap,一个用于存储机器ID,一个用于存储序列号。假设机器ID和序列号分别需要存储10位和12位,那么我们可以定义两个长度为(2^10)/8=128和(2^12)/8=256的byte数组,分别用于存储机器ID和序列号。 在生成ID时,先根据雪花算法生成一个64位的ID,然后将其中的机器ID和序列号分别使用Bitmap算法进行压缩,最终将压缩后的结果拼接成一个新的ID,并返回。 下面是一个简单的Java实现示例: ```java public class SnowflakeIdGenerator { private long lastTimestamp = -1L; private long sequence = 0L; private long workerId; private Bitmap workerIdBitmap; private Bitmap sequenceBitmap; public SnowflakeIdGenerator(long workerId) { this.workerId = workerId; this.workerIdBitmap = new Bitmap(1 << 10); this.sequenceBitmap = new Bitmap(1 << 12); } public synchronized long nextId() { long timestamp = System.currentTimeMillis(); if (timestamp < lastTimestamp) { throw new RuntimeException("Clock moved backwards"); } if (timestamp == lastTimestamp) { sequence = (sequence + 1) & 0xFFF; if (!sequenceBitmap.get((int) sequence)) { sequenceBitmap.set((int) sequence); } else { return nextId(); } } else { sequence = 0L; sequenceBitmap = new Bitmap(1 << 12); } lastTimestamp = timestamp; if (!workerIdBitmap.get((int) workerId)) { workerIdBitmap.set((int) workerId); } long id = ((timestamp << 22) | (workerId << 12) | sequence); return id; } } ``` 在上面的示例中,我们定义了一个SnowflakeIdGenerator类,其中包含一个机器ID和两个Bitmap。在nextId方法中,先使用雪花算法生成一个原始的64位ID,然后将其中的机器ID和序列号压缩到对应的Bitmap中,最终拼接成一个新的ID,并返回。 需要注意的是,在压缩机器ID和序列号时,我们使用了两个长度分别为1 << 10和1 << 12的Bitmap。这是因为机器ID和序列号的位数分别为10位和12位。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值