40亿QQ号,不超过1G内存,如何去重?

40 亿 QQ 号(64 位整数级别)内存不超过 1GB 的条件下做去重,经典可行方案只有「位图(Bitmap / BitSet) 」,甚至进阶到「布隆过滤器」。

我给你讲最可落地的几种方案,按工程可行性来排:

✅ 最优方案:Bitmap(位图,精确去重)

1. 内存计算

假设 QQ 号范围:

最大约 10~11 位数字 ,最大值约 4,000,000,0000(按 400 亿上限算)。

但常见按 40 亿(4×10⁹) 来设计: 40 亿 bit ≈ 4,000,000,000 bits = 500,000,000 bytes ≈ 477 MB

结论:
Bitmap 完全可以在 1GB 内存内精确去重

2. 核心思想

用 bit 数组来表示某个 QQ 是否出现过:

  • 位置 = QQ号
  • 值 = 0 → 未出现
  • 值 = 1 → 已出现

读取每个 QQ:

  • 如果该位为 0 → 标记为 1
  • 如果已经是 1 → 说明重复

3. Java 示例代码(可直接运行)

java 复制代码
import java.io.BufferedReader;
import java.io.FileReader;


public class QQDedupBitmap {

    // 假设最大QQ号 = 4_000_000_000
    static final long MAX_QQ = 4_000_000_000L;
    static final int BIT_PER_BYTE = 8;

    public static void main(String[] args) throws Exception {
        // 分配位图
        byte[] bitmap = new byte[(int)(MAX_QQ / BIT_PER_BYTE + 1)];

        BufferedReader br = new BufferedReader(new FileReader("/Users/longjun/Downloads/qq.txt"));
        String line;

        while ((line = br.readLine()) != null) {
            long qq = Long.parseLong(line.trim());
            long index = qq / 8;
            int offset = (int)(qq % 8);

            if ((bitmap[(int)index] & (1 << offset)) != 0) {
                // 重复
                // 你可以输出或统计
                System.out.println("重复的QQ号:" + qq);
            } else {
                bitmap[(int)index] |= (1 << offset);
            }
        }
        br.close();
        // 恢复QQ号
        recoverQQFast(bitmap);
    }

    /**
     * 快速恢复QQ号
     * @param bitmap
     */
    public static void recoverQQFast(byte[] bitmap) {
        for (int i = 0; i < bitmap.length; i++) {
            int b = bitmap[i] & 0xFF;
            while (b != 0) {
                int offset = Integer.numberOfTrailingZeros(b);
                long qq = (long) i * 8 + offset;
                System.out.println(qq);
                b &= (b - 1);
            }
        }
    }
}

如果 QQ 号范围极大(比如 10¹² 级别)

Bitmap 不现实,使用:

✅ 布隆过滤器(Bloom Filter)

特点:

特点 说明
内存占用小 比 HashSet 小 10 倍以上
误判率 存在(会把新数据误认为重复)
不会漏判 重复一定判重复

适合场景:

  • 爬虫 URL 去重
  • 用户 ID 去重
  • 海量日志去重

Java 布隆过滤器实现(精简版)

java 复制代码
import java.util.BitSet;
import java.util.zip.CRC32;

public class BloomFilter {
    private BitSet bitSet;
    private int size;

    public BloomFilter(int size) {
        this.size = size;
        this.bitSet = new BitSet(size);
    }

    private int hash(long value, int seed) {
        long h = value ^ (value >>> 16) * seed;
        return (int)(Math.abs(h) % size);
    }

    public boolean isDuplicate(long value) {
        int h1 = hash(value, 31);
        int h2 = hash(value, 131);
        int h3 = hash(value, 1313);

        if (bitSet.get(h1) && bitSet.get(h2) && bitSet.get(h3)) {
            return true;
        }
        bitSet.set(h1);
        bitSet.set(h2);
        bitSet.set(h3);
        return false;
    }
}

🚀 超大数据工程级方案

当数据根本放不下内存:

  1. 外部排序 + 归并去重
  2. Hash 分桶 -> 小文件去重
  3. Hadoop / Spark

✅ 总结一句

在「40 亿 QQ 号 + 内存不超过 1GB」这个条件下:

目标 最优方案
精确去重 Bitmap 位图 ✅
允许误判 布隆过滤器 ✅
相关推荐
毕设源码-钟学长12 分钟前
【开题答辩全过程】以 基于Springboot的扶贫众筹平台为例,包含答辩的问题和答案
java·spring boot·后端
程序员良许41 分钟前
三极管推挽输出电路分析
后端·嵌入式
Java水解1 小时前
【JAVA 进阶】Spring AOP核心原理:JDK与CGLib动态代理实战解析
后端·spring
Java水解1 小时前
Spring Boot 4 升级指南:告别RestTemplate,拥抱现代HTTP客户端
spring boot·后端
宫水三叶的刷题日记1 小时前
工商银行今年的年终奖。。
后端
大黄评测1 小时前
双库协同,各取所长:.NET Core 中 PostgreSQL 与 SQLite 的优雅融合实战
后端
Java编程爱好者1 小时前
Java 后端定时任务怎么选:@Scheduled、Quartz 还是 XXL-Job?
后端
Java编程爱好者1 小时前
线程池用完不Shutdown,CPU和内存都快哭了
后端
神奇小汤圆1 小时前
Unsafe魔法类深度解析:Java底层操作的终极指南
后端
神奇小汤圆2 小时前
浅析二叉树、B树、B+树和MySQL索引底层原理
后端