【算法与数据结构专场】BitMap算法基本操做代码实现

上篇咱们讲了BitMap是如何对数据进行存储的,没看过的能够看一下【算法与数据结构专场】BitMap算法介绍java

这篇咱们来说一下BitMap这个数据结构的代码实现。算法

回顾下数据的存储原理

一个二进制位对应一个非负数n,若是n存在,则对应的二进制位的值为1,不然为0。数组

这个时候,咱们的第一个问题:数据结构

咱们在使用byte,int,short,long等这些数据类型在存储数据的时候,他们最小的都要占用一个字节的内存,也就是8个bit,也就是说,最小的操做单位是8个bit。根本就没有能够一个一个bit位操做的数据类型啊。优化

在Java的bitMaP实现中,它采用的是用一个long数据来进行存储的。一个long占用8个字节,即64bit,因此一个long能够存储64个数。例如 arr 是一个long 类型的数组,则 arr[0]能够存 0 ~ 63,arr[1]能够存64 ~127,以此类推。this

不过,咱们就采用byte数组的来存吧。一个byte占用一个字节,即8bit,能够存8个数字。spa

固然,你要采用long数组来存也能够。在实现上能够说是同样的。code

例如咱们要存储(1,3,5,7,8,10)时,他们的内存以下所示。cdn

下面咱们就来说讲如何对一个一个位进行操做的。blog

如何向bitmap中添加一个数值

咱们先来讲说如何在bitmap中如何添加一个数值的问题,例如咱们咱们要添加n=14。

这个其实很简单,咱们先找到n在arr数组中的下标index,显然index = 1。而后再找到n在arr[index]中的位置position,显然这里position = 6。

这里仍是能够很容易找出index和position的公式的。即

index = n / 8 = n >> 3。

position = n % 8 = n & 0x07。

接下来咱们把1向右移动position个二进制位,而后把所得的结果和arr[index]作“或(or)”操做就能够了。以下图

这里有个须要注意的地方,在画图的时候,为了方便,咱们是把左边的位看成低位,右边的位看成高位来算了。不过在实际的存储中,左边的才是存高位,而右边的存的是低位。因此在咱们的代码实现中,咱们所说的右移对应代码的左移。

代码实现

//添加数据的操做

public void add(int n){
    //用>>的操做是,运算会比较快
    int index = n >> 3;
    int position = n & 0x07;
    //把1右移和作or操做两步一块儿
    //即 << 对应上图的右移,实际上<<是左移符。
    arr[index] |= 1 << position;
}
复制代码

知道了add操做,其余的操做差很少相似。

固然,咱们实现的add操做只是简单的实现一下,假如你要严谨地实现的话,仍是须要不少异常的判断的。例如判断这个数是不是非负数,判断arr数组是否下标越界,进行容量的扩充等等。有兴趣的能够严谨去实现一下。

删除操做。

咱们只须要把对应的二进制的1变成0就能够了。

咱们能够把1右移(代码中对应左移)后的结果取反,而后与arr[index]作“与”操做就能够了。代码以下:

public void delete(int n){
    int index = n >> 3;
    int position = n & 0x07;
    arr[index] &= ~(1 << position);
}
复制代码

判断是否存在操做

咱们把1右移以后,把结果和arr[index]作“与”操做,如何结果不为0,则证实存在,不然就不存在。

public boolean contain(int n){
    int index = n >> 3;
    int position = n & 0x07;
    return (arr[index] & (1 << position)) != 0;
}

复制代码

三个最基本的操做代码基本实现了。

但愿你们可以去实践一下。

所有代码:

public class BitMap {
    private byte[] arr;
    //容量,即最多可以存多少个数据
    private int capacity;

    public BitMap(int capacity) {
        this.capacity = capacity;
        //一个byte能够存8个数据,capacity实际上指的是多少个bit
        arr = new byte[(capacity / 8 + 1)];
    }

    //添加数据的操做

    public void add(int n){
        //用>>的操做是,运算会比较快
        int index = n >> 3;
        int position = n & 0x07;
        //把1右移和作or操做两步一块儿
        //即 << 对应上图的右移,实际上<<是左移符。
        arr[index] |= 1 << position;
    }

    public void delete(int n){
        int index = n >> 3;
        int position = n & 0x07;
        arr[index] &= ~(1 << position);
    }

    public boolean contain(int n){
        int index = n >> 3;
        int position = n & 0x07;
        return (arr[index] & (1 << position)) != 0;
    }
}
  
复制代码

问题

你们看了以上的代码,有没发现一些问题呢?

例如咱们只在bitmap存储1个数,而且存的数值是2000000000,咱们就会在第2000000000个二进制把0改成1。也就是说arr数组的大小至少为2000000000/8+1。但是这时候前面的二进制位并无存数据,那不是超级超级浪费资源?

因此说,像咱们上面的那种写法能够说是暴力写法,没有通过任何优化,实际上,在Java自带的bitMap中是有不少优化的,并不会像咱们上面实现的代码同样那么浪费空间资源。有兴趣的能够研究下。

至于如何优化,我会在以后的文章讲,尽情期待。

获取更多原创文章,能够关注下个人公众号:苦逼的码农,我会不按期分享一些资源和软件等。后台回复礼包送你一份时下热门的资源大礼包,同时也感谢把文章介绍给更多须要的人

相关文章
相关标签/搜索