java中BitMap实现

本文介绍了一种利用BitMap结构高效存储和管理大量稀疏数据的方法。通过具体的实现步骤和代码示例,展示了如何将一个整数映射到BitMap中的特定位置,并实现了插入和查询的功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考的博客地址:http://blog.youkuaiyun.com/xqy1522/article/details/7901141

int中32位只能表示一个数,而用BitMap可以表示32一个数:
int[] bitMap:
bitMap[0]:可以表示数字0~31 比如表示0:00000000 00000000 00000000 00000000
比如表示1 : 00000000 00000000 00000000 00000001
bitMap[1]:可以表示数字32~63
bitMap[2]:可以表示数字64~95
……
因此要将一个数插入到bitMap中要进过三个步骤:
1)找到所在bitMap中的index也就是bitMap数组下标
比如我们要在第64一个位置上插入一个数据(也就是插入63)
index = 63 >> 5 = 1,也就是说63应该插入到bitMap[1]中
2)找到63在bitMap[1]中的偏移位置
offset = 63 & 31 = 31说明63在bitMap[1]中32位的最高位
3)将最高位设为1

具体代码如下:

package com.xll;
/**
 * 实现BitMap
 * 
 * @author xialonglei
 * @since 2016/5/26
 */
public class BitMap {
    /** 插入数的最大长度,比如100,那么允许插入bitsMap中的最大数为99 */
    private long length;
    private static int[] bitsMap;
    private static final int[] BIT_VALUE = { 0x00000001, 0x00000002, 0x00000004, 0x00000008, 0x00000010, 0x00000020,
            0x00000040, 0x00000080, 0x00000100, 0x00000200, 0x00000400, 0x00000800, 0x00001000, 0x00002000, 0x00004000,
            0x00008000, 0x00010000, 0x00020000, 0x00040000, 0x00080000, 0x00100000, 0x00200000, 0x00400000, 0x00800000,
            0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000 };
    public BitMap(long length) {
        this.length = length;
        // 根据长度算出,所需数组大小
        bitsMap = new int[(int) (length >> 5) + ((length & 31) > 0 ? 1 : 0)];
    }
    /**
     * 根据长度获取数据 比如输入63,那么实际上是确定数62是否在bitsMap中
     * 
     * @return index 数的长度
     * @return 1:代表数在其中 0:代表
     */
    public int getBit(long index) {
        if (index < 0 || index > length) {
            throw new IllegalArgumentException("length value illegal!");
        }
        int intData = (int) bitsMap[(int) ((index - 1) >> 5)];
        return ((intData & BIT_VALUE[(int) ((index - 1) & 31)])) >>> ((index - 1) & 31);
    }
    /**
     * @param index
     *            要被设置的值为index - 1
     */
    public void setBit(long index) {
        if (index < 0 || index > length) {
            throw new IllegalArgumentException("length value illegal!");
        }
        // 求出该index - 1所在bitMap的下标
        int belowIndex = (int) ((index - 1) >> 5);
        // 求出该值的偏移量(求余)
        int offset = (int) ((index - 1) & 31);
        int inData = bitsMap[belowIndex];
        bitsMap[belowIndex] = inData | BIT_VALUE[offset];
    }
    public static void main(String[] args) {
        BitMap bitMap = new BitMap(63);
        bitMap.setBit(63);
        System.out.println(bitMap.getBit(63));
        System.out.println(bitMap.getBit(62));
    }
}

结果图:
0
1

### 如何用 Java 实现 Bitmap 签到功能 为了实现基于 Redis 的 Bitmap 用户签到功能,可以通过 Spring Data Redis 来集成 Redis 并利用其提供的 Bitmap 数据结构。以下是完整的代码示例以及相关说明。 #### 1. 添加依赖 首先,在项目中引入必要的 Maven 或 Gradle 依赖项来支持 Redis 和 Spring Data Redis: ```xml <!-- Maven --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> </dependency> ``` 或者使用 Gradle: ```gradle implementation 'org.springframework.boot:spring-boot-starter-data-redis' implementation 'com.fasterxml.jackson.core:jackson-databind' ``` --- #### 2. 配置 Redis 连接 配置 `application.yml` 文件中的 Redis 参数: ```yaml spring: redis: host: localhost port: 6379 password: lettuce: pool: max-active: 8 max-idle: 8 min-idle: 0 ``` --- #### 3. 编写签到逻辑代码 下面是一个简单的签到功能实现代码示例: ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Service; import java.time.LocalDate; @Service public class CheckInService { @Autowired private StringRedisTemplate stringRedisTemplate; /** * 用户签到方法 * * @param userId 用户ID */ public void checkIn(String userId) { LocalDate today = LocalDate.now(); long dayOfYear = today.getLong(java.time.temporal.ChronoField.DAY_OF_YEAR); stringRedisTemplate.opsForValue().setBit(userId, dayOfYear, true); // 设置当前日期对应的 bit 值为 1 [^4] } /** * 查询某天是否已签到 * * @param userId 用户ID * @param date 要查询的日期 * @return 是否已签到 */ public boolean isCheckedInOnDate(String userId, LocalDate date) { long dayOfYear = date.getLong(java.time.temporal.ChronoField.DAY_OF_YEAR); return Boolean.TRUE.equals(stringRedisTemplate.opsForValue().getBit(userId, dayOfYear)); // 获取指定日期的 bit 值 } /** * 统计连续签到天数 * * @param userId 用户ID * @return 连续签到天数 */ public int countConsecutiveCheckIns(String userId) { LocalDate today = LocalDate.now(); long currentDay = today.getLong(java.time.temporal.ChronoField.DAY_OF_YEAR); int consecutiveDays = 0; while (currentDay >= 0 && Boolean.TRUE.equals(stringRedisTemplate.opsForValue().getBit(userId, currentDay))) { // 循环判断连续签到情况 consecutiveDays++; currentDay--; } return consecutiveDays; } } ``` --- #### 4. 测试代码 编写单元测试验证签到功能是否正常运行: ```java @SpringBootTest class CheckInServiceTest { @Autowired private CheckInService checkInService; @Test void testCheckIn() { String userId = "testUser"; // 执行签到 checkInService.checkIn(userId); // 验证当天是否已签到 assertTrue(checkInService.isCheckedInOnDate(userId, LocalDate.now())); // 计算连续签到天数 assertEquals(1, checkInService.countConsecutiveCheckIns(userId)); } } ``` --- #### 关键点解析 1. **存储优化** 使用 Bitmap 存储用户的签到记录能够显著减少内存消耗。例如,每月仅需 4 字节即可保存每天的签到状态[^3]。 2. **高效操作** Redis 提供了专门的操作命令(如 SETBIT、GETBIT),可以直接对位图进行设置和读取,性能极高。 3. **扩展性** 如果系统是分布式的,则可以选择 Redis 作为集中化的存储方案,便于跨服务访问和管理[^1]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值