2017-01-11 10 views
-2

ファイルから大量のデータを読み込みます。必要な見出しを持つ100の異なるデータオブジェクトが存在する可能性がありますが、これらのデータオブジェクトのそれぞれに300,000を超える値が格納されている可能性があります。 。値は、これは、データオブジェクトのコンストラクタでそれらが読み込まれるのと同じ順序に格納する必要があります大量のデータを保持するのに最適なデータ構造ですか?

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

RAMに順次、これらの値を格納および取得する最も簡単な方法でしょうか?

+0

順序が重要なので、 'Queue'インタフェースを実装するデータ構造体を使用します。 'LinkedList'など –

+0

ArrayListの何が問題なのですか?これらの要素にランダムアクセスが必要ですか? –

+0

「最も効率的」とはどういう意味ですか?少なくとも記憶を取る?最も速く書く?順番に読むのが最も速い?最も速く検索する(どの基準で検索しますか?)これまでに何を試してみましたか、それはなぜ「効率的」ではないと思いますか? – slim

答えて

-2

RedBlack BSTを使用すると、データを保存/取得するための非常に効率的な方法になります。これは他のノードにリンクしているノードに依存しているので、Javaのメモリが十分にある限り、入力のサイズに制限はありません。

0

あなたのコメントでは、 "クイック"である必要がある操作を指定せずに "クイックネス"と言いますが、主な関心事はヒープメモリ消費のようです。

300,000の数字の100個のグループを考えてみましょう(あなたは "may be"や "over over"のような単語を使用しましたが、これは例として行います)。

これは、格納する30,000,000の数字と、100個の見出しと、グループ化のための構造上のオーバーヘッドです。

プリミティブJava floatは、4バイトです。したがって、最低限、30,000,000 * 4バイト== 120MBが必要になります。

プリミティブの配列--float[30000000] - は、連続したメモリチャンクに連結されたすべての値なので、この理論的最小値は120MBで、アレイのオーバーヘッドあたり1バイトのオーバーヘッドを消費しますここで詳しく説明します。

Java Floatラッパーオブジェクトは12バイトです。プリミティブではなくオブジェクトを配列に格納する場合、参照自体は4バイトです。したがって、Float - Float[30000000]の配列は、30,000,000 *(12 + 4)== 480MBを消費します。

したがって、ラッパーではなくプリミティブを使用することで、メモリ使用量を半分以上削減できます。


ArrayListObjectの配列の周りにはかなり軽いラッパーですので、同じメモリのコストについては持っています。 1回のリスト当たりのオーバーヘッドは、これらのリストサイズでは要素に比べて影響が小さくなりすぎます。しかし、いくつかの注意点があります。

  • ArrayListができる唯一のストアオブジェクトではなくプリミティブは、あなたがListを選択した場合、あなたはFloatの12バイトあたりの要素オーバーヘッドで立ち往生しているそう。プリミティブのリストを提供し、いくつかのサードパーティ製のライブラリがあります
  • ArrayListの容量は動的であり、そしてあなたがより大きくなるために、リストを育てる場合は、これを達成するために、その配列をバックアップ、それがされます:
    • 古い配列よりも50%も大きい新しい配列を作成するには、これは高価に聞こえる(新しい配列に古い配列の内容をコピーしますが、ハードウェアがこれを行うには非常に高速です)
    • これは補助配列を30万個の要素を持つように発生し、いっぱいになった場合、ArrayList.add()はあなたのListだけで30,000,001を必要とする場合でも、4500万要素の一つで配列を置換することを意味し、古い配列
    • を捨てます。
    • 事前に必要な容量がわかっている場合は、コンストラクタの容量を指定することでこれを回避できます。
    • ArrayListを入力した後で、ArrayList.trimToSize()を使用して不要な容量を削除し、メモリをクローズすることができます。

      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); 
    } 
} 

、ファイルを2回通過することを検討 - 一度グループの長さを発見するために、もう一度あなたの配列を埋めるために。

あなたはに持って場合は、1回のパスでファイルを消費し、ファイル形式は、グループの前にグループの長さを提供することができない、あなたが任意に成長する「リスト」を可能にする何かをする必要があります。いくつかのオプションがあります:

  • ArrayList<Float>に、各グループの消費 - グループが完了したときに、array[float]に変換:

    float[] array = new float[list.size()]; 
    int i = 0; 
    for (Float f : list) { 
        array[i] = f; // auto-unboxes Float to float 
    } 
    
  • サードパーティのリスト・オブ・フロートライブラリクラスを使用します
  • コピーし、必要なときに1より大きくして、あなたの配列を置き換えるためのArrayListで使用されるロジック - http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/ArrayList.java#ArrayList.ensureCapacity%28int%29
  • コンピュータ科学の教科書で議論のアプローチの任意の数、例えばのリンクリストアレイ。

しかし、これのどれも最初の場所でのメモリにすべてのこれらの数字をズルズルためのあなたの理由を考慮していない、またそれが数字を処理することになると、この店はあなたのニーズを満たしているかどうか。

実際のデータ処理要件が何であるか、そしてメモリへのスラッピングが最適なアプローチであるかどうかを検討する必要があります。

全体をメモリに保存するのではなく、一度にデータスライスのみを保存することで処理できるかどうかを確認してください。たとえば、最大/最小/平均を計算するには、すべての数値をメモリに格納する必要はありません。実行中の合計を保持するだけで済みます。

または、軽量データベースライブラリの使用を検討してください。

関連する問題