位图的实现
前言:
hashset,用来存储key,天然帮你去重了,比如存储5,6,8,int类型的数,然后hashset可以查看5在不在这个集合中,但是int是4byte,32bit,用一个4字节的存储才能判断某个数在不在,用32位的一个空间才能表示一个数字在不在hash表里面,更不用说hash表自己内部还有别的空间消耗,这就非常的浪费空间。
这就引入了位图的概念。位图是什么呢?也许这个数的范围非常有限,此时就可以不用hash表,用更省空间的位图的方式。例如已知所有的数字是从0~10000,一个数字进来就耗4字节,太费了。
假设arr数组,里面有a,b,c,d...,a可以表示0~31这些数字有没有出现;b可以表示32~63这些数字有没有出现...比如1出现了,那么就在a的0位上标1。
那么要表示0~1000这些数有没有出现,至少需要几个数字呢?需要:1000/32个数字,即arr数组的长度为1000/32。
1、位图的实现思路:
package com.cy.code;
/**
* 位图的实现
* Bitset是一种能以紧凑形式存储位的数据结构
* Bitset(int n): 初始化n个位,所有位都是0
* void fix(int i): 将下标i的位上的值更新为1
* void unfix(int i): 将下标i的位上的值更新为0
* void flip(): 翻转所有位的值
* boolean all(): 是否所有的位都是1
* boolean one(): 是否至少有一位是1
* int count(): 返回所有位中1的数量
* String toString(): 返回所有位的状态
* 测试连接:https://leetcode-cn.com/problems/design-bitset/
*/
public class Code08_DesignBitsetTest {
/**
* 一、查询
* 假设数组长度为400,请问400这个数有没有出现?
* 400应该是在数组的下标位置:400 / 32
* 在第几位呢?400 % 32
* 再右移这么多位得到一个数
* 再和1进行&运算,得到0或1, 0表示不存在,1表示存在
*
* 二、修改
* 怎么让num进入位图,在相应的位置上标1,如果之前就是1,那就维持1
* 先定位到数组的下标: arr[num / 32]
* 改数组的这个数的哪一位呢? num % 32
* 再将1左移这么多位得到结果,再将这个结果与原数组的数arr[num / 32]进行或运算
*
* 三、删除
* 怎么让num进入位图,在相应的位置上标记0
*/
public static void main(String[] args) {
// arr[0] -> 0 ~ 31
// arr[1] -> 32 ~ 63
int[] arr = new int[400];
int num = 400;
int status = (arr[num / 32] >> (num % 32)) & 1;
// 修改,num加入到arr中,如果之前有的话,就继续维持
arr[num / 32] = arr[num / 32] | (1 << (num % 32));
arr[num / 32] |= 1 << (num % 32);
//修改,num从arr中删除
arr[num / 32] = arr[num / 32] & (~(1 << (num % 32)));
}
}
删除,怎么让num进入位图,在相应的位置上标记0呢?
思路草图:
二、位图的代码实现:
--