如何在1G内存下对40亿QQ号去重?Java高效解决方案

问题背景与挑战
  • 数据规模:40亿QQ号,假设每个QQ号为32位无符号整数(最大值2³²-1 ≈ 42.9亿)

  • 内存限制:1GB ≈ 1,073,741,824字节(1024³)

  • 传统方法缺陷

    • HashSet存储40亿数据需要约 64GB内存(每个Long对象约16字节)
    • 直接加载到内存会导致OOM(OutOfMemoryError)

核心技术:位图法(Bitmap)

核心思想:每个bit位表示一个数字是否存在
优势

  1. 内存极致压缩:40亿数据仅需 512MB内存(40亿bit ÷ 8 ÷ 1024³ ≈ 476MB)
  2. 时间复杂度O(1) :判断和插入均为位运算

Java实现详细设计
1. 位图结构设计
  • 为什么不用Java内置BitSet?
    Java的BitSet内部使用long[]存储,但最大理论容量为Integer.MAX_VALUE位(约20亿),无法覆盖40亿数据

  • 自定义位图实现

    public class Bitmap {
         
        private final long[] words; // 使用long数组存储位信息
        private static final int ADDRESS_BITS_PER_WORD = 6; // 2^6 = 64
    
        public Bitmap(long maxNum) {
         
            // 计算需要多少个long元素:ceil((maxNum + 1) / 64)
            int numWords = (int) ((maxNum >>> ADDRESS_BITS_PER_WORD) + 1);
            this.words = new long[numWords];
        }
    
        /**
         * 检查并设置位(原子操作)
         * @return true表示已存在,false表示首次插入
         */
        public boolean containsAndSet(long num) {
         
            int wordIndex = (int) (num >>> ADDRESS_BITS_PER_WORD);
            int bitIndex = (int) (num & 0x3F); // 等价于 num % 64
            long mask = 1L << bitIndex

你可能感兴趣的:(面试,后端,java)