位运算的应用--->位图

首先我们先了解一下什么是位图。

首先我们知道一个int类型的数据再内存中是以二级制的方式储存,但是怎么用二进制的方式来存储数据,那么就把每个二进制位当作标记,用来标记第每个数字是否存储,那么如果是二进制的话那么我们就只能标记0~31中,其中的数字是否有进行存储,那么如果我们需要进行存储更多,那么我们就需要运用到数组,因为数组是一份连续的存储空间。假如我们需要存储0~63,那么我们就需要一个int[2],的数组来进行存储,同时还可以选择一个long类型的数据来进行存储。

我们只需要选择一个存储的最大的数据,我们就可以选择我们存储的最大类型。

位图简单的就是利用二进制来进行做标记,0--->没有这个数,1--->有这个数。

第一个二进制表示,0这个数有没有,

第二个二进制表示,有没有1这个数,

.............

第八个二进制位表示,有没有8这个数,

.............

第二十个二进制表示,有没有20这个数。

这样我们就可以利用二进制位来表示我们的数字集合------>(BitMap 位图)。

集合的成员属性

private long[] bits;
    private int max;
    private int min;

首先我么利用bits这个数组来表示我们一连串的二进制位,同时我们设置了最大值和最小值,用来确定我们所需要的的集合大小

public BitMap(int max){
        this(max,0);
    }
    public BitMap(int max,int min){
        this.max = max;
        this.min = min;
        bits = new long[(max-min+64)>>6];
    }

我们通过最大值和最小值来进行判断我们所需要的最小空间。

首先我们先计算max到min之间有几个数字(包括最大值和最小值)。

max-min+1

同时我们要知道一个long类型时是64个比特位,所以我们要计算我们的数组需要多大,所以我们就需要整体除以64。

但是当我们我们最大值和最小值之间的数字是小于64的时候相除会导致数组的无法统计部分数字。

所以我们进行成体加上63,这样就能保证能够满足条件。

位图的添加元素

 public void add(int value){
        value = value-min;
        bits[(value)>>6] |= (1L<<(value & 63));
    }

首先我们要根据我们需要的元素进行判断我们需要添加的元素在第几个long。

同时我们要进行取模操作。但是我们并不是直接使用取模操作符。

例如:

二进制数 1100101011101101010

63------->0000000000000111111

进行&操作00000000000101010

相当于大于64的前面全部忽略。(运用位运算代替取模操作是能运用到2^n)

用1L向前左移value的取模数。

相当于前1000000(64)的数字用来确定在第几个long,

后面的数字用来确定这个数的位置long的第几个bit。

删除

public void delete(int num){
        if(num>=min && num<=max){
            num = num-min;
            bits[num>>6] &= ~(1L << (num & 63));
        }
    }

首先我们需要知道删除的数字是否在最大值和最小值之间。

同时我们要在知道这个数字在第几个long,

同时我们用取模之后的数字进行进行判断在第几个比特位,同时我们依然是选择之前的方法找到。

但是删除就需要将找到位置后的数字进行取反。例如:

找到第几个比特位之后:

000000000010000000000000000

取反之后

111111111101111111111111111

原本bits[(value)>>6] 的数字

010101100111000010010010101

进行&操作

010101100011000010010010101

判断某个数是否存在。

public boolean conatins(int num){
        if(num>max && num<min){
            return false;
        }else{
            num = num-min;
            return (bits[num>>6] & (1L << (num & 63))) !=0;
        }
    }

首先我们需要和之前一样找到我们需要判断的num所在的第几个long。

然后我们用之前添加数字的方式找到该数所对应的比特位

我们再用整个long与(1L<<(num & 63))进行&操作,然后判断是不是为0.

import java.util.HashSet;

public class BitMap {
    private long[] bits;
    private int max;
    private int min;
    public BitMap(int max){
        this(max,0);
    }
    public BitMap(int max,int min){
        this.max = max;
        this.min = min;
        bits = new long[(max-min+64)>>6];
    }
    public void add(int value){
        value = value-min;
        bits[(value)>>6] |= (1L<<(value & 63));
    }
    public void delete(int num){
        if(num>=min && num<=max){
            num = num-min;
            bits[num>>6] &= ~(1L << (num & 63));
        }
    }
    public boolean conatins(int num){
        if(num>max && num<min){
            return false;
        }else{
            num = num-min;
            return (bits[num>>6] & (1L << (num & 63))) !=0;
        }
    }

    public static void main(String[] args) {
        boolean flag = true;
        int max = 99999999;
        int min = 999;
       for(int j = 0;j<5;j++){
           do{
               max = (int)(Math.random() * (max+1));
               min = (int)(Math.random() * (min+1));
           }while (max<=min);
           BitMap map = new BitMap(max,min);
           HashSet<Integer> set = new HashSet<>();
           int testTime = 50000000;
           int num = 0;

           for(int i = 0;i<testTime;i++){
               do{
                   num = (int)(Math.random() * (max+1));
               }while(num<min);
               double decide = Math.random();
               if(decide<0.33){
                   map.add(num);
                   set.add(num);
               }else if(decide<0.66){
                   map.delete(num);
                   set.remove(num);
               }else{
                   if(map.conatins(num)!=set.contains(num)){
                       flag = false;
                       break;
                   }
               }
           }
           for(int t = min; t<= max; t++){
               if(map.conatins(t) !=set.contains(t)){
                   flag = false;
                   break;
               }
           }
       }
        System.out.println(flag ? "Nice" : "Fucking fucked");
    }


}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值