我有一个由小到大排序的随机整数序列,其中数字从1位开始,接近45位。在列表的开头,我有一些非常接近的数字:4、20、23、40和66。但是随着数字的增加,它们之间的距离也会略微增加(实际上它们之间的距离是随机的)。没有重复的数字。
我正在使用位压缩来节省一些空间。尽管如此,这个文件可能会变得非常大。
我想知道在这种情况下可以使用什么样的压缩算法,或者任何其他技术来尽可能地节省空间。
谢谢。
我有一个由小到大排序的随机整数序列,其中数字从1位开始,接近45位。在列表的开头,我有一些非常接近的数字:4、20、23、40和66。但是随着数字的增加,它们之间的距离也会略微增加(实际上它们之间的距离是随机的)。没有重复的数字。
我正在使用位压缩来节省一些空间。尽管如此,这个文件可能会变得非常大。
我想知道在这种情况下可以使用什么样的压缩算法,或者任何其他技术来尽可能地节省空间。
谢谢。
void Compress(std::ostream& os,
const std::vector<unsigned long>& v,
unsigned long k = 0) {
BitOut out(os);
out.put(v.size(), 64);
if (v.size()) {
unsigned long twok;
if (k == 0) {
unsigned long ratio = v.back() / v.size();
for (twok = 1; twok <= ratio / 2; ++k, twok *= 2) { }
} else {
twok = 1 << k;
}
out.put(k, 32);
unsigned long prev = 0;
for (unsigned long val : v) {
while (val - prev >= twok) { out.put(1); prev += twok; }
out.put(0);
out.put(val - prev, k);
prev = val;
}
}
out.flush(1);
}
解压:
std::vector<unsigned long> Decompress(std::istream& is) {
BitIn in(is);
unsigned long size = in.get(64);
if (size) {
unsigned long k = in.get(32);
unsigned long twok = 1 << k;
std::vector<unsigned long> v;
v.reserve(size);
unsigned long prev = 0;
for (; size; --size) {
while (in.get()) prev += twok;
prev += in.get(k);
v.push_back(prev);
}
}
return v;
}
使用可变长度编码可能有些麻烦;一种替代方法是将每个编码的第一个位(1或0)存储在位向量中,将k比特的后缀存储在另一个向量中。如果k为8,则这将特别方便。
一种变体,会导致稍微更长的文件,但更容易构建索引,只使用1位作为增量。然后增量始终为a·2k,其中a是紧随后缀代码的连续1位数目,可以为0。索引由位向量中每Nth个1位的位置以及相应的后缀向量索引(即与位向量中下一个0对应的后缀索引)组成。
过去我使用过的一种很好的方法是将64位整数存储为8个不同的8位值列表。首先存储数字的高8位,然后是接下来的8位,以此类推。例如,假设您有以下32位数字:
0x12345678
0x12349785
0x13111111
0x13444444
12,12,13,13
34,34,11,44
56,97,11,44
78,85,11,44
我随后将其通过deflate压缩器运行。
我不记得我能够使用这种方法实现什么压缩比,但它比直接压缩数字本身要好得多。
我希望能提供一种最简单的解决方案:
我认为这在您的情况下将会得到几乎完美的结果,因为距离具有简单的分布规律。7-zip将能够处理它。
第一部分的数字将在0-45之间,即使有很多数字。因此,它们可以通过像哈夫曼这样的熵编码进行有效压缩。