Java 压缩数字数组

Java 压缩数字数组,java,arrays,performance,compression,Java,Arrays,Performance,Compression,我有一个大数组(~400.000.000个条目),其整数为{0,1,…,8}。 所以我每个条目需要4位。大约200 MB 目前,我使用字节数组,并在每个条目中保存2个数字 我想知道,是否有一个好的方法来压缩这个数组。我做了一个快速的研究,发现了像哈夫曼或LZW这样的算法。但是这些算法都是用于压缩数据,将压缩后的数据发送给某人并解压缩 我只想有一个表,有更少的内存空间,所以我可以加载到RAM。200MB的表很容易安装,但我正在考虑更大的表 重要的是,我仍然能够确定某些位置上的值 有什么建议吗 进

我有一个大数组(~400.000.000个条目),其整数为{0,1,…,8}。 所以我每个条目需要4位。大约200 MB

目前,我使用字节数组,并在每个条目中保存2个数字

我想知道,是否有一个好的方法来压缩这个数组。我做了一个快速的研究,发现了像哈夫曼或LZW这样的算法。但是这些算法都是用于压缩数据,将压缩后的数据发送给某人并解压缩

我只想有一个表,有更少的内存空间,所以我可以加载到RAM。200MB的表很容易安装,但我正在考虑更大的表

重要的是,我仍然能够确定某些位置上的值

有什么建议吗


进一步资料: 我只是做了一点实验,结果表明,平均2.14个连续数字都有相同的值。 有1个零,154个一,10373个二,385990个三,8146188个四,85008968个五,265638366个六,70791576个七和80个八。 所以超过一半的数字是6


我只需要一个快速的getValue(idx)函数,setValue(idx,value)并不重要

这取决于数据的外观。是否有重复的条目,或者它们只是缓慢地改变,或者什么

如果是这样,您可以尝试压缩数据块,并在需要时解压缩。块越大,可以节省的内存越多,速度越慢。我没有什么好交易。您还可以将压缩和解压缩的数据保存在内存中

否则,也就是说,在没有规则的情况下,每个条目至少需要
log(9)/log(2)=3.17
位,没有什么可以改善它

通过将5个数字压缩成一个
short
,可以非常接近此值。由于
9**5=59049<65536=2**16
,它几乎完全适合。每个数字需要
3.2
位,没有大的成功。五个数字的包装通过这个公式给出

a + 9 * (b + 9 * (c + 9 * (d + 9 * e)))
通过预计算的表进行解包是很简单的

问题更新后更新 进一步信息:我只是做了一点实验,结果表明,平均2.14个连续数字都有相同的值。有1个零,154个一,10373个二,385990个三,8146188个四,85008968个五,265638366个六,70791576个七和80个八。所以超过一半的数字是6

事实上,平均有2.14个连续的数字是相同的,这可能会导致一些压缩,但在这种情况下,这说明我们什么都没有。几乎只有五和六,所以遇到两个相等的连续数字似乎是隐含的

鉴于这些事实,您可以忘记我的上述优化。实际上只有8个值,因为您可以单独处理单个零。因此,每个值只需要3位,零只需要一个索引

您甚至可以为4以下或7以上的所有值创建一个
HashMap
,在那里存储1+154+10373+385990+80个条目,每个值仅使用2位。但这还远远不够理想

假设没有正则性,则每个值需要1.44位,因为这是最简单的。您可以检查所有5个元组,计算它们的直方图,并使用1字节对255个最频繁的元组进行编码。所有剩余的元组都将映射到第256个值,告诉您必须在
HashMap
中查找罕见的元组值

一些评价 我很好奇它是否能起作用。将5个数字打包成一个字节需要85996340字节。有近500万个元组不合适,所以我的想法是使用哈希映射。假设重新灰化而不是链接,保持50%的容量是有意义的,所以我们需要1000万个条目。假设(将索引映射到元组)每个条目占用6个字节,即60 MB。太糟糕了

将4个数字打包成一个字节将消耗107495425个字节,并留下159531个不合适的元组。这看起来更好,但是,我相信更密集的包装可以改进很多

这一点产生的结果如下:


您应该查看
位集
,以最有效地存储它。与名字所暗示的相反,它并不完全是一个集合,它有顺序,你可以按索引访问它

在内部,它使用一个
long
s数组来存储位,因此可以使用位掩码进行自我更新


<>我不相信你可以更有效地存储它,如果你想提高效率,那么你应该考虑打包/压缩算法。

< P>如何考虑一些缓存解决方案,比如,或。这将使您能够将集合持久化到磁盘,从而使您能够处理非常大的列表。

有许多选项,大部分取决于数据的外观。您可以使用以下任何一种,甚至是它们的组合

在您的情况下,使用4位初始字典的变体可能是一个良好的开端

您可以将数据压缩成块,这样就可以使用请求的索引来确定要动态解码的块

如果数据中存在重复的模式,这将是一个很好的选择

差分编码 您的编辑表明您的数据可能会从差异传递中受益。从本质上讲,您可以用每个值与其前一个值之间的差异来替换每个值

同样,您需要以块和不同的固定运行长度来处理数据

您还可能会发现,使用LZW跟随的差分法将是一个很好的解决方案

如果一些数据丢失是可以接受的,那么一些傅里叶变换压缩方案可能是有效的

如果您的数据是二维的,那么一些JPEG算法本身可能会很好地进行lebd

底线 你需要记住:

  • 压缩时间越长(达到一定限度),压缩率就越高
  • 无损压缩的实际应用范围是有限的
  • 一旦你迷失了方向,你就变得至关重要
    *** Packing 5 numbers in a byte. ***
    Normal packed size: 85996340.
    Number of tuples in need of special handling: 4813535.
    
    *** Packing 4 numbers in a byte. ***
    Normal packed size: 107495425.
    Number of tuples in need of special handling: 159531.
    
                            encoding               total   
               #entrie      bit pattern  #bits    # of bits
     zero            1      000000001      9              9
     ones          154      0000001        7           1078  
     twos        10373      000001         6          62238
     threes     385990      00001          5        1929950
     fours     8146188      0001           4       32584752
     fives    85008968      01             2      170017936
     sixes   265638366      1              1      265638366
     sevens   70791576      001            3      212374728
     eights         80      00000001       8            640
    --------------------------------------------------------
     Total                                        682609697 bits
    
                                    Estimated pos   Offset from
    # entry no   Actual Position     (n * 1.59)      estimated
         0             0                  0               0      
       100           162                159               3      Use this 
       200           332                318              14  <-- column as   
       300           471                477              -6      the index
       400           642                636               6
       500           807                795              12
       600           943                954             -11