算法---BitMap

摘要:
=0;}/*** 删除标记*@paramval*@return*/publicvoid Remove{int index=val/32;location=val%32;System.out.println;flag[index]=flag[idex]&~;//~反转1到00到1 System.out.print;}publicstaticvoid main{BitMapbitMap=newBitMap;bitMap.put;bitMap.prout;System.out.pintln;System.out.println然而,它仍然有它的缺点。如果我们上面使用的数字是其他类型的,我们可能需要在哈希之后获取哈希代码来执行此操作。解决哈希冲突是不可能的。布隆过滤器使用bitMap的思想。然而,它也将使用集中式哈希算法来计算哈希代码,以尝试解决哈希冲突。JDK中还有一个BitSet类。

问题:

假设有3亿个整数(范围0-2亿),如何判断某一个树是否存在。局限条件一台机器,内存500m

常规的思路:我们可以将数据存到一个集合中,然后判断某个数是否存在;或者用一个等长的数组来表示,每个数对应的索引位置,存在就标记为1,不存在0。当然如果设备条件允许,上面的这方案是可行的。

但是现在我们内存只有500mInt类型4个字节。

单单是这3亿个数都已经:300000000*4/1024/1024 差不多1144m了。显然已经远超过内存限制了。

显然在这种条件下面,我们想要将这些书完整的存储下来已经是不现实的。只有另寻他经。

上面的第二种方案中提供一个很好思路,用标记来标注。我们只有寻求内存占用更小的数据类型来标记了,1int=4byte,1byte = 8bit

如果我们用bit来打标记。就不可以很好的缩小内存占用了嘛。1int=4byte,如果用bit那么内存占用就会缩小32倍,1144/32大概36m就可以了。

也就是说其实我们的一个int位置,可以表示32个数据存在与否

Int 1的二进制完整表示:0000 0000 0000 0000 0000 0000 0000 0001,它是有32位,只不过平时前面的0都是没有显示的

我们声明一个int类型的标记数组:flag[2亿/32 +1],数组长度2亿/32 +1,就可以了,为什么是2亿/32,不是3亿呢,因为这3亿个数的范围就是0-2亿,所以我们的标记数组最大只需要对应2亿即可。有的数,就将其标记为1。就是说数组的没一个元素其实包含了32个数存在与否。

Flag[0] --->0-31

Flag[1] --->32-63

Flag[2] --->64-95

Flag[3] --->96-127

.......

我们怎么来操作这个int类型里面的32位呢,这就要用到我们的位运算:

<<:左移

>>:右移

&:同位上的两个数都是1则位1,否则为0

|:同为上的两个数只要有一个为1 则为1,否则为0

我们怎么找到某个数的标记在数组的索引及其值的多少位呢?

假设3这个数

Index = 3 / 32 = 0

Location = 3 % 32 = 3

3的标记应该在flag[0] 的第三个位置,将其置为1

flag[0]  |=  1 << Location (位或是不会影响其他位置1的标记)

原本的flag[0]  0000 0000 0000 0000 0000 0000 0000 0011    原本已经有了01

     |    0000 0000 0000 0000 0000 0000 0000 1000    1 << Location 之后的

得到:           0000 0000 0000 0000 0000 0000 0000 1011    现在有0,1,3

这样就可以所有的数据标记给保存下来了。

那么判断的时候怎么判断呢。

同理先找到某个数精确位置

还是3

Index = 3 / 32 = 0

Location = 3 % 32 = 3

现在我们的flag[0] -> 0000 0000 0000 0000 0000 0000 0000 1011

Exist = flag[0] & (1 << Location) != 0  &:相同位上的两个数都是1则位1,否则为0

  0000 0000 0000 0000 0000 0000 0000 1011

&  0000 0000 0000 0000 0000 0000 0000 1000

    0000 0000 0000 0000 0000 0000 0000 1000

&运算之后结果不为0说明该数存在。

大致的思路就是这个样子,下面用代码实现上述逻辑

package com.nijunyang.algorithm.math;

/**
 * Description:
 * Created by nijunyang on 2020/5/5 22:33
 */
public class BitMap {
    /**
     * 范围中最大的那个数
     */
    private int max;

    private int[] flag;

    public BitMap(int max) {
        this.max = max;
        flag = new int[max >> 5 + 1]; //除以32也可以表示为>>5
    }

    /**
     * 添加数据标记
     * @param val
     */
    public void put(int val) {        //往bitmap里面添加数字

        int index = val / 32;        // 计算数组索引位置
        int location = val % 32;    // 计算在32位int中的位置
        flag[index] |= 1 << location;   //标记位改成1
    }

    /**
     * 判断是否存在
     * @param val
     * @return
     */
    public boolean exist(int val) {
        int index = val / 32;
        int location = val % 32;

        int result = flag[index] & (1 << location);
        return result != 0;
    }

    /**
     * 移除标记
     * @param val
     * @return
     */
    public void remove(int val) {
        int index = val / 32;
        int location = val % 32;

        System.out.println(Integer.toBinaryString(flag[index]));
        flag[index] = flag[index] &~ (1 << location); //~取反1变0 0变1
        System.out.println(Integer.toBinaryString(flag[index]));
    }

    public static void main(String[] args) {
        BitMap bitMap = new BitMap(200_000_000);
        bitMap.put(128);
        bitMap.put(129);
        System.out.println(bitMap.exist(127));
        System.out.println(bitMap.exist(128));
        bitMap.remove(128);
        System.out.println(bitMap.exist(128));

    }
}

虽然说用bitMap的这种思想可以解决上面的这个问题,但是它还是有缺点的,我们上面用的数字,如果是其他类型可能就需要hash之后得到hashcode再进行这个操作,对于hash冲突是无法解决的。因为标记只有01。数据量少的时候相对于普通的hash集合操作并没有优势。它对于那种数据量很大,且数据相对密集的,因为数组的长度是和最大的数据值有关,而不是和集合容量有关。

布隆过滤器就使用bitMap的思想。不过它同时会使用集中hash算法来计算hashcode,来尽量解决hash冲突。Redis缓存设计与性能优化 中有简单的介绍。

JDK中也有一个BitSet类。

免责声明:文章转载自《算法---BitMap》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇宇宙信息能量的沟通WCF服务下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Bitmap 转字节流字符, 压缩等处理

//压缩后转字节字符 public String bitmaptoString(Bitmap bitmap) { // 将Bitmap转换成字符串 String string = null; ByteArrayOutputStream baos = new ByteArrayOutputStream(); bitmap.compress(Bitma...

[转]android 获取视频帧

本文转自:http://blog.csdn.net/heart_Moving/article/details/17414067 今天做Android视频文件解码,需求:从一个视频文件获取到一帧一帧的图片。 总结如下: 首先看代码: MediaDecoder.java [html]view plaincopyprint? import android...

[BOT] 一种android中实现“圆角矩形”的方法

内容简介 文章介绍ImageView(方法也可以应用到其它View)圆角矩形(包括圆形)的一种实现方式,四个角可以分别指定为圆角。思路是利用“Xfermode + Path”来进行Bitmap的裁剪。 背景 圆角矩形实现的方法应该很多,网上一大堆。很怀疑为啥安卓的控件不内置这样的属性(我不知道有)? 之前用到的网络图片加载库(UniversalImageL...

【Android】缩略图Thumbnails

在Android,多媒体文件(视频和图片)都是有缩略图的,在很多应用中,我们需要获取这些缩略图。比如最近在做一个类似相册的应用,需要扫描相册里面的图片,然后获取其缩略图,使用GridView去展示缩略图,当点击之后,我们需要获取其原始图,所以相关的需求如下: 1)获取缩略图(一个问题是:是否所有的图片以及视频都有缩略图?); 2)将缩略图和原始图关联起来;...

BitBlt 函数 详解, StretchBlt、SetStretchBltMode、SetBrushOrgEx 按句柄截图、直接截取缩略图

BitBlt 该函数对指定的源设备环境区域中的像素进行位块(bit_block)转换,以传送到目标设备环境。 函数原型 [DllImport("gdi32.dll")] public static extern bool BitBlt(IntPtr hObject, int nXDest, intnY...

关于View转化成bitmap保存成图片

产品今天说项目分享时要分享出一张  封面图片 + 几行文字 + 二维码图片 的图片。 思索了一下 封面图片和二维码图片让后台给接口得到地址, 主要还是找个方式得到一个包含这些内容的图片。于是就想能不能将View转化成bitmap对象 然后就走了一遍各个前辈的路 整理了下原理和思路。        根据产品的需求  我要实现的步骤  把所有需要的集合在一个V...