算法与数据结构——位图BitMap

一、介绍

1.1 什么是位图

在Java中有四种整数类型:byteshortintlong
1 byte(字节) = 8 bit(位)
1 int = 4 byte = 32 bit

所以我们可以通过一个int整数来表示32个数字!
如现在有一个整数0,他的二进制有32位。
打印二进制位:

    /**
     * 打印二进制
     * 从0位开始到31位
     * @param num
     */
    public static void printNum(int num){
        for (int i = 31; i >= 0; i--) {
            System.out.print((num & (1<<i)) == 0 ? "0": "1");
        }
        System.out.println();
    }

在这里插入图片描述
我们可以通过将32位上的第几位标记为1来表示数字有没有出现过。
例如:

00000000000000000000000000000000 来表示0
00000000000000000000000000000001 表示1出现
00000000000000000000000000000010 表示2出现
00000000000000000000000000000100 表示3出现
....
10000000000000000000000000000000 表示31出现

这样通过一个数字就可以表示32个数字。可以极大的节省内存空间。
这样在数组中:
第1个数字表示的范围为0 ~ 31;
第2个数字表示的范围为32 ~ 63;
第3个数字表示的范围为64 ~ 95;
第4个数字表示的范围为96 ~ 127;
第5个数字表示的范围为128 ~ 159;

依次类推

例如:
如果我想要表示92102这个数字出现过,则用92102除以32,找出在数组上的第几位数字。所以92102这个数字在数组上第2878个数的范围内,接下来找这个数字上的第几位,取92102模上32的余数 ,即在数组上第2878个数二进制的6位,标记为1。标志92102这个数字出现过。

1.2 怎么标记

上面的思路有了,接下来就是怎么实现了标记和取消标记。
将一个整数的32位二进制上的第几位标记为1
将哪一位标记为1,可以让该位置和1| 或操作。

在这里插入图片描述
(注意:从第0位开始,到第7位,所以标记在第八位)

1.3 怎么取消标记

将二进制位上的1设置为0:
如:00000000000000000000000010000000 第7位上已经标记为1了,现在要取消,即该位设置为0。
即让该位置和1进行与 & 操作即可。
在这里插入图片描述

1.4 判断该位置是否标记

标记1 可以表示添加一个数字;
标记0 可以表示删除一个数字;
我们还需要 一个方法来 判断这个数字是否存在? 即是否标记1。
可以通过该位置上和1 &与操作 ,如果都为1 则

在这里插入图片描述

二、代码实现

    public static class BitMap{

        public int[] bits;

        /**
         * 初始化数组的长度,最大值(补上一位) 除以32 即表示数组最大多少长度可以表示这个最大值。
         * @param max 表示此位图结构中存储的最大的值
         */
        public BitMap(int max){
            //(max + 32) >> 5   等同于  (max + 32)/32
            bits = new int[(max + 32)>>5];
        }

        /**
         * 通过或操作
         * 向位图里添加一个数
         * 00000000000000000000000000000001
         * 00000000000000000000000000010000
         * 与操作
         * 00000000000000000000000000010001 将该位置标记为1
         * @param num
         */
        public void add(int num){
            //首先判断是在数组的哪一位上表示  除以32
            //再判断这位整数上的第几位 模上32 取余数即表示第几位
            //把这个位标记为1 即 与上1<<第几位
            //bits[num >> 5] = bits[num >> 5] | 1<<(num % 32 ) 就等同于bits[num >> 5]  |=   1<<(num % 32 )
            //bits[num >> 5] = bits[num >> 5] | 1<<(num % 32 );
            //注意:
            //%64(除以64后的余数) 等同于 &63(与63) ,因为63的二进制表示为111111
            //所以num % 32 等同于  num & 31
            bits[num >> 5]  |=   1<<(num & 31 );
        }

        /**
         * 从位图里删除一个数
         * 和(余数取反)与操作
         *
         * 该位置数:00000000000000000000000000100001
         * 余数:   00000000000000000000000000000001
         * 余数取反:11111111111111111111111111111110
         * 与操作: 00000000000000000000000000000001
         * 即该位置上的1消除,表示此数值已删除
         * @param num
         */
        public void del(int num){
            //通过&与操作将数组上第几位的数字上的该位置清空
            bits[num >> 5]  &=   ~(1<<(num & 31 ));
        }

        /**
         * 查看位图中是否包含这个数
         * @param targetNum 目标数
         * @return  是否包含
         */
        public boolean contains(int targetNum){
            //该位置上的数 和32的余数 与操作如果不为0 则存在 否则不存在
            return (bits[targetNum >> 5] & (1 << (targetNum & 31))) != 0;
        }
    }

三、测试

在这里插入图片描述

    public static void main(String[] args) {
        //新建一个最大值为1000的位图
        BitMap bitMap = new BitMap(1000);
        System.out.println("数组长度:"+bitMap.bits.length);
        System.out.println("是否包含100:"+bitMap.contains(100));
        //添加操作 :100/32 = 3...4 ;即把数组第4个元素的第4位标记为1
        bitMap.add(100);
        printNum(bitMap.bits[3]);
        System.out.println("是否包含100:"+bitMap.contains(100));
        //删除操作
        bitMap.del(100);
        System.out.println("是否包含100:"+bitMap.contains(100));
    }
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Liu_Shihao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值