これらのトークンをメモリ内で 1 ~ 2Mbで表現し、O(1)
ルックアップをサポートすることは非常に困難です。標準のコレクション型でこれを行うことはできません。また、サードパーティの Java ライブラリでこれを行うことも知りません。( S-SpaceプロジェクトにはTrieSet
実装がありますが、コードを調べたところ、スペースまたはパフォーマンスの要件を満たしていないと確信しています ...)
文字列内の文字が ASCII であると仮定すると、それらを String オブジェクトに変換するとすぐにサイズが 2 倍になり ( byte
-> char
)、文字列ごとに 32 バイトのオーバーヘッドを追加する必要があります。次に、文字列を に入れるHashSet
と、セット内のエントリごとに約 32 バイトが追加で必要になります。
ArrayList<String>
エントリごとのオーバーヘッドは 4 バイトですが、ルックアップは...O(N)
またはO(logN)
、リストの順序を維持してバイナリ検索を使用する場合です。いずれにせよ、メモリの予算をまだ超えています。
予算内に収まるようにするには、メモリ使用量が最適化されたカスタム ハッシュ テーブル データ構造を使用し、文字データを単一のバイト配列としてメモリに保持する必要があります。
これは仮想的な実装です。
int[]
をハッシュ配列に割り当てます。サイズは、トークン数の約半分から 5 分の 1 の素数にする必要があります。
byte[]
トークンのファイルを保持するのに十分な大きさを割り当てます。
- ハッシュ配列の各スロットについて:
- ファイルをバイト単位でスキャンして、ハッシュコードがスロットにマップされているすべてのトークンを探します。
- 各トークンをバイト配列にコピーし、その後にターミネータ バイトを続けます。
- トークンが見つかった場合は、最初のトークンの開始のバイト配列オフセットをハッシュ配列スロットに書き込みます...そうでない場合は、に設定し
-1
ます。
- ルックアップを行うには:
- テスト文字列をバイトに変換し、
- テスト文字列のバイトを (上記と同じハッシュ アルゴリズムを使用して) ハッシュし、それをハッシュ スロットにマップします。
- ハッシュ スロットのオフセットから開始して、テスト文字列のバイトを のバイトと比較します
byte[]
。一致するか、次のハッシュ配列要素のオフセットに到達するまで繰り返します。
ご覧のとおり、入力するプロセスにはbyte[]
、入力ファイルを複数回スキャンすることが含まれます。ただし、これは事前に行うことができ、必要な順序でバイトを含むように入力ファイルを更新することができます。
スペースの使用量は、文字列データのバイトごとに 1 バイト + 文字列ごとに 1 バイトのオーバーヘッド + プライマリ ハッシュ配列のスロットごとに 4 バイト (+ 雑多なO(1)
オーバーヘッド) になります。ルックアップはO(1)
平均的ですが、定数はハッシュ配列のサイズによって異なります。(大きければ大きいほど良いです。)
上記の設計の大きな欠点は次のとおりです。
- データ構造の作成にはコストがかかります
- スペースまたは時間効率の良い方法でデータ構造を更新することはできません
- セットを反復する場合は、一連の String オブジェクトを作成してエントリを表すか、バイト配列とオフセットを公開する必要があります。