保存大量数据的最佳数据结构?

时间:2017-01-11 16:30:36

标签: java data-structures

从文件中读取大量数据。可能有100个不同的数据对象具有必要的标题,但每个数据对象中可以存储超过300,000个值。这些值需要以与读入它们相同的顺序存储。这是数据对象的构造函数:

public Data(String heading, ArrayList<Float> values) {
    this.heading = heading;
    this.values = values;
}

在RAM中按顺序存储和检索这些值的最快方法是什么?

2 个答案:

答案 0 :(得分:1)

虽然在你的评论中你提到&#34; quickness&#34;,但没有指明需要什么操作&#34;快速&#34;,你的主要关注点似乎是堆内存消耗。

让我们假设有100组300,000个数字(你已经使用像#34这样的单词;可能是&#34;和#34;远远超过&#34;但这将作为一个例子)

要存储的30,000,000个数字,加上100个标题和一些用于分组的结构开销。

原始Java float是32位,即4个字节。所以绝对最低限度,你需要30,000,000 * 4字节== 120MB。

一个基元数组 - float[30000000] - 只是连接成一个连续的内存块的所有值,所以将消耗120MB的理论最小值 - 加上每个数组一次的几个字节开销我们不会在这里详细介绍。

java Float包装器对象是12个字节。在数组中存储对象(而不是基元)时,引用本身是4个字节。因此,Float - Float[30000000]数组将消耗30,000,000 *(12 + 4)== 480MB。

因此,您可以使用原语而不是包装器将内存使用量削减一半以上。

ArrayList围绕Object数组是一个很轻的包装器,因此具有相同的内存成本。在这些列表大小中,每个列表的一次性开销太小而不能与元素相比产生影响。但有一些警告:

  • ArrayList只能存储对象,而不能存储基元,因此,如果选择List,则会遇到Float的每个元素12个字节的开销。
  • ArrayList的容量是动态的,为实现此目的,如果将列表增大到大于其后备数组,它将:
    • 创建一个比旧数组大50%的新数组
    • 将旧数组的内容复制到新数组中(这听起来很昂贵,但硬件执行速度非常快)
    • 丢弃旧阵列
    • 这意味着如果支持数组恰好有3000万个元素并且已满,ArrayList.add()将使用4500万个元素中的一个替换该数组,即使您的List仅需要30,000,001。< / LI>
    • 如果您事先知道所需的容量,可以通过在构造函数中提供容量来避免这种情况。
    • 您可以使用ArrayList.trimToSize()删除不需要的容量,并在填充ArrayList后重新留下一些记忆。

如果我努力使用尽可能少的堆内存,我的目标是将我的数字列表存储为基元数组:

 class Data {
     String header;
     float[] values;
 }

......我想把它们放到ArrayList<Data>

使用此结构,您可以对任意值进行O(1)访问,并且可以使用Arrays.binarySearch()(如果值已排序)在组中按值查找。

如果可能的话,我会在读取值之前找出每个组的大小,并将数组初始化为正确的大小。如果可以,请输入您的输入文件格式:

 while(line = readLine()) {
     if(isHeader(line)) {
          ParsedHeader header = new ParsedHeader(line);
          currentArray = new float[header.size()];
          arrayIndex = 0;
          currentGroup = new Group(header.name(), currentArray);

          groups.add(currentGroup);
     } else if (isValue(line)) {
          currentArray[arrayIndex++] = parseValue(line);
     }
 }

如果您无法更改输入格式,请考虑在文件中进行两次传递 - 一次发现组长度,再次填充数组。

如果您必须一次性使用该文件,并且文件格式无法在群组之前提供群组长度,那么您必须做一些允许& #34;列表&#34;随意成长有几种选择:

然而这些都没有考虑到你首先将所有这些数字压入内存的原因,也不考虑这个商店在处理数字时是否满足你的需求。

您应该退后一步,考虑一下您的实际数据处理要求是什么,以及是否啜饮内存是最好的方法。

通过一次只存储一片数据来查看是否可以进行处理,而不是将整个内容存储在内存中。例如,要计算最大/最小/平均值,您不需要每个数字都在内存中 - 您只需要保持运行总计。

或者,考虑使用轻量级数据库库。

答案 1 :(得分:-2)

您可以使用RedBlack BST,这将是一种非常有效的存储/检索数据的方式。这依赖于链接到其他节点的节点,因此只要有足够的内存用于java,输入的大小就没有限制。