经典算法- BitMap

原文链接https://www.jianshu.com/p/6082a2f7df8e

一、问题引入

举一个例子,有一个无序有界int数组{1,2,5,7},初步估计占用内存4X4=16字节,这倒是没什么奇怪的,但是假如有10亿个这样的数呢,如果这样的一个大的数据做查找和排序,那估计内存也崩溃了,有人说,这些数据可以不用一次性加载,那就是要存盘了,存盘必然消耗IO。我们提倡的是高性能,这个方案直接不考虑。

二、问题分析

bitmap: 基于位的映射

一个byte是占8个bit,如果每一个bit的值就是有或者没有,也就是二进制的0或者1,如果用bit的位置代表数组值有还是没有,那么0代表该数值没有出现过,1代表该数组值出现过。不也能描述数据了吗?具体如下图:

在这里插入图片描述
这样,一个占用32bit的数据现在只占用了1bit,节省了不少的空间,排序就更不用说了,一切显得那么顺利。这样的数据之间没有关联性,要是读取的,你可以用多线程的方式去读取。时间复杂度方面也是O(Max/n),其中Max为byte[]数组的大小,n为线程大小。
处。

三、应用与代码

基于bit运算实现

再看代码之前,我们先搞清楚一个问题,一个数怎么快速定位它的索引号,也就是说搞清楚byte[index]的index是多少,position是哪一位。举个例子吧,例如add(14)。14已经超出byte[0]的映射范围,在byte[1]范围之类。那么怎么快速定位它的索引呢。如果找到它的索引号,又怎么定位它的位置呢。Index(N)代表N的索引号,Position(N)代表N的所在的位置号。

Index(N) = N/8 = N >> 3;

Position(N) = N%8 = N & 0x07;

1. add(int num)

你要向bitmap里add数据该怎么办呢,不用担心,很简单,也很神奇。
上面已经分析了,add的目的是为了将所在的位置从0变成1.其他位置不变.
下图应是作或运算 )
在这里插入图片描述
实例代码

public void add(int num){
        // num/8得到byte[]的index
        int arrayIndex = num >> 3; 
        
        // num%8得到在byte[index]的位置
        int position = num & 0x07; 
        
        //将1左移position后,那个位置自然就是1,然后和以前的数据做或运算,这样,那个位置就替换成1了。
        bits[arrayIndex] |= 1 << position; 
    }

2. clear(int num)

对1进行左移,然后取反,最后与byte[index]作与操作。
在这里插入图片描述

public void clear(int num){
        // num/8得到byte[]的index
        int arrayIndex = num >> 3; 
        
        // num%8得到在byte[index]的位置
        int position = num & 0x07; 
        
        //将1左移position后,那个位置自然就是1,然后对取反,再与当前值做&,即可清除当前的位置了.
        bits[arrayIndex] &= ~(1 << position); 

    }

3. contain(int num)

在这里插入图片描述

 public boolean contain(int num){
        // num/8得到byte[]的index
        int arrayIndex = num >> 3; 
        
        // num%8得到在byte[index]的位置
        int position = num & 0x07; 
        
        //将1左移position后,那个位置自然就是1,然后和以前的数据做&,判断是否为0即可
        return (bits[arrayIndex] & (1 << position)) !=0; 
    }

全部代码

package com.chs.alg.bitmap;

public class BitMap {
    //保存数据的
    private byte[] bits;
    
    //能够存储多少数据
    private int capacity;
    
    
    public BitMap(int capacity){
        this.capacity = capacity;
        
        //1bit能存储8个数据,那么capacity数据需要多少个bit呢,capacity/8+1,右移3位相当于除以8
        bits = new byte[(capacity >>3 )+1];
    }
    
    public void add(int num){
        // num/8得到byte[]的index
        int arrayIndex = num >> 3; 
        
        // num%8得到在byte[index]的位置
        int position = num & 0x07; 
        
        //将1左移position后,那个位置自然就是1,然后和以前的数据做|,这样,那个位置就替换成1了。
        bits[arrayIndex] |= 1 << position; 
    }
    
    public boolean contain(int num){
        // num/8得到byte[]的index
        int arrayIndex = num >> 3; 
        
        // num%8得到在byte[index]的位置
        int position = num & 0x07; 
        
        //将1左移position后,那个位置自然就是1,然后和以前的数据做&,判断是否为0即可
        return (bits[arrayIndex] & (1 << position)) !=0; 
    }
    
    public void clear(int num){
        // num/8得到byte[]的index
        int arrayIndex = num >> 3; 
        
        // num%8得到在byte[index]的位置
        int position = num & 0x07; 
        
        //将1左移position后,那个位置自然就是1,然后对取反,再与当前值做&,即可清除当前的位置了.
        bits[arrayIndex] &= ~(1 << position); 

    }
    
    public static void main(String[] args) {
        BitMap bitmap = new BitMap(100);
        bitmap.add(7);
        System.out.println("插入7成功");
        
        boolean isexsit = bitmap.contain(7);
        System.out.println("7是否存在:"+isexsit);
        
        bitmap.clear(7);
        isexsit = bitmap.contain(7);
        System.out.println("7是否存在:"+isexsit);
    }
}

四、bitmap排序实例

以下参考https://wizardforcel.gitbooks.io/the-art-of-programming-by-july/content/06.07.html

//定义每个Byte中有8个Bit位  
#include <memory.h>  
#define BYTESIZE 8  
void SetBit(char *p, int posi)  
{  
    for(int i=0; i < (posi/BYTESIZE); i++)  
    {  
        p++;  
    }  

    *p = *p|(0x01<<(posi%BYTESIZE));//将该Bit位赋值1  
    return;  
}  

void BitMapSortDemo()  
{  
    //为了简单起见,我们不考虑负数  
    int num[] = {3,5,2,10,6,12,8,14,9};  

    //BufferLen这个值是根据待排序的数据中最大值确定的  
    //待排序中的最大值是14,因此只需要2个Bytes(16个Bit)  
    //就可以了。  
    const int BufferLen = 2;  
    char *pBuffer = new char[BufferLen];  

    //要将所有的Bit位置为0,否则结果不可预知。  
    memset(pBuffer,0,BufferLen);  
    for(int i=0;i<9;i++)  
    {  
        //首先将相应Bit位上置为1  
        SetBit(pBuffer,num[i]);  
    }  

    //输出排序结果  
    for(int i=0;i<BufferLen;i++)//每次处理一个字节(Byte)  
    {  
        for(int j=0;j<BYTESIZE;j++)//处理该字节中的每个Bit位  
        {  
            //判断该位上是否是1,进行输出,这里的判断比较笨。  
            //首先得到该第j位的掩码(0x01<<j),将内存区中的  
            //位和此掩码作与操作。最后判断掩码是否和处理后的  
            //结果相同  
            if((*pBuffer&(0x01<<j)) == (0x01<<j))  
            {  
                printf("%d ",i*BYTESIZE + j);  
            }  
        }  
        pBuffer++;  
    }  
}  

int _tmain(int argc, _TCHAR* argv[])  
{  
    BitMapSortDemo();  
    return 0;  
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值