在 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;
}
}
🚀 超大数据工程级方案
当数据根本放不下内存:
- 外部排序 + 归并去重
- Hash 分桶 -> 小文件去重
- Hadoop / Spark
✅ 总结一句
在「40 亿 QQ 号 + 内存不超过 1GB」这个条件下:
| 目标 | 最优方案 |
|---|---|
| 精确去重 | Bitmap 位图 ✅ |
| 允许误判 | 布隆过滤器 ✅ |