Bitmap算法

简介

一个公司有8个员工,每个员工有一个ID号(1B表示),员工的上班记录:
1.N个字节记录每个员工的情况
2.8bit记录员工的情况00101111(0表示上班)

优点:存储空间小,便于进行交叉运算(and,xor,or,not)
关键技术:压缩存储RLE
这里写图片描述

可以编码为0,8,2,11,1,2,3,11
其意思是:第一位为0,连续有8个,接下来是2个1,11个0,1个1,2个0,3个1,最后是11个0

应用

  • 对数据进行快速地查找,判重,删除;(要求数据不重复)
  • 去除重复数据达到压缩

1.对10亿个不重复的数据进行排序

假设用int表示一个数据,因为int为4字节,那么最多可以表示2^31-1即20亿的数据,满足题目10亿数据的要求,如果将这些数据按int存储,则需要的总空间为(10^9)*4/(1024*1024*1024)大概是4G左右,我们可以用bitmap来存储元素 "key,value"的形式

以“小端存储”为例,假设要存1,5,7,2,13

这里写图片描述
那么以前是4byte表示1位,现在是1bit表示1位,则实际需要的空间是4G/32不到0.1G左右,可以节约大量的内存空间

代码

下面介绍bitmap中的几种常见操作

1.clear 所有的bit置0

比如要将4置为,那么只需要构造出11101111,然后与b[0]求&操作即可。这可以将1左移4为,然后取反
假定要将数字i置为0
思路:
1.首先要确定i位于哪一个数组中
0~7 位于b[0]
8~15位于b[1]
16~23位于b[2]

可以推测i的数组下标为i/8,即index=i>>3
2.要计算i在当前8bit中的位置,即要求1应当左移几位
数字 位
0 0
1 1
2 2

7 7
8 0
9 1
10 2
总结:shift=i%8,即shift = i & 0x07;
3.置0
a[index] = a[index] & (~(1<<shift));

2.将某一位置为1,即存储

例如要存储4,构造出00010000,然后求或即可
1.首先找到数组的小标index
2.找到左移的位数shift
3.置1

3.判断当前位是否含1

仍然以4为例,只要与00010000求&,然后判断结果是否为0即可得知该位是否为1

4.输出排序后的结果

从0~10亿逐位判断是否为1

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

typedef unsigned char byte;
#define MAX_NUM 1000000000

byte a[MAX_NUM/8]; //数组大小


//找到数组的下标
int get_index(int i)
{
    return i>>3;//即i/8
}

//找到位移的次数
int get_shift(int i)
{
    return i & 0x07;//即i%8
}


void clear(int i)
{

    int index= get_index(i);    
    int shift = get_shift(i); 
    //置0
    a[index] &= (byte)(~(1<<shift));
}


void set(int i)
{
    int index= get_index(i);    
    int shift = get_shift(i); 

    a[index] |= ((byte)(1<<shift));
}

void clear_all(int max_num=MAX_NUM)
{
    for(int i=0;i<=max_num;i++)
        clear(i);
}

void bit_map(int array[], int size,int max_num=MAX_NUM)
{
    clear_all(max_num);
    for(int i=0;i<size;i++)
    {
        set(array[i]);
    }
}

//返回1,表示存在
int contain(int i)
{
    int index= get_index(i);    
    int shift = get_shift(i); 

    int exist = a[index] &(1<<shift);
    return exist;
}


void print(int max_num)
{
    for(int i=0;i<=max_num;i++)
    {
        if(contain(i))
            cout<<i<<' ';
    }
    cout<<endl;
}


int main()
{

    int m[]={21,25,10,12,14};
    int size=5;
    bit_map(m,size,21);
    print(21);

    return 0;
}

http://blog.csdn.net/hguisu/article/details/7880288
http://www.infoq.com/cn/articles/the-secret-of-bitmap

雪花算法是一种生成分布式唯一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、付费专栏及课程。

余额充值