听起来使用利用数据结构的自定义压缩机制可能非常有效。
首先,使用short[]
(16 位数据类型)而不是int[]
将发送的数据量减半(!),您可以这样做,因为数字很容易介于-2^15
(-32768) 和2^15-1
(32767) 之间。这非常容易实现。
其次,您可以使用类似于游程编码的方案:正数从字面上表示该数字,而负数表示那么多零(在取绝对值之后)。例如
[10, 40, 0, 0, 0, 30, 0, 100, 0, 0, 0, 0] <=> [10, 40, -3, 30, -1, 100, -4]
这更难实现,只是替换short
,int
但在最坏的情况下会提供约 80% 的压缩(1000 个数字,100 个非零,没有一个是连续的)。
我只是做了一些模拟来计算压缩比。我测试了上面描述的方法,以及 Louis Wasserman 和 sbridges 建议的方法。两人的表现都非常好。
假设数组的长度和非零数字的数量都在它们的界限之间,这两种方法平均节省了大约 5400int
秒(或short
秒),压缩大小约为原始的 2.5%!游程编码方法似乎额外节省了大约 1 个int
(或平均压缩大小小 0.03%),即基本上没有区别,因此您应该使用最容易实现的一种。以下是 50000 个随机样本的压缩率直方图(它们非常相似!)。
摘要:使用short
s 代替int
s 和其中一种压缩方法,您将能够将数据压缩到其原始大小的 1% 左右!
对于模拟,我使用了以下 R 脚本:
SIZE <- 50000
lengths <- sample(1000:10000, SIZE, replace=T)
nonzeros <- sample(1:100, SIZE, replace=T)
f.rle <- function(len, nonzero) {
indexes <- sort(c(0,sample(1:len, nonzero, F)))
steps <- diff(indexes)
sum(steps > 1) + nonzero # one short per run of zeros, and one per zero
}
f.index <- function(len, nonzero) {
nonzero * 2
}
# using the [value, -1 * number of zeros,...] method
rle.comprs <- mapply(f.rle, lengths, nonzeros)
print(mean(lengths - rle.comprs)) # average number of shorts saved
rle.ratios <- rle.comprs / lengths * 100
print(mean(rle.ratios)) # average compression ratio
# using the [(index, value),...] method
index.comprs <- mapply(f.index, lengths, nonzeros)
print(mean(lengths - index.comprs)) # average number of shorts saved
index.ratios <- index.comprs / lengths * 100
print(mean(index.ratios)) # average compression ratio
par(mfrow=c(2,1))
hist(rle.ratios, breaks=100, freq=F, xlab="Compression ratio (%)", main="Run length encoding")
hist(index.ratios, breaks=100, freq=F, xlab="Compression ratio (%)", main="Store indices")