頻度を計算する必要があるというコメントの後に追加されました。
データに期待する単語の数や、単語を構成するものは何も言いません。英語の文章だとしたら、50万語を見てびっくりします。そして、5ギガバイトのテキストに10億語が含まれることは確かにありません。しかし、単語の数に関係なく、テクニックは実際には変わりません。
まず、キーと値のペア(単語、カウント)を含む辞書またはハッシュマップを作成します。各単語を読みながら、辞書で調べてください。そこにある場合は、その数を増やします。そこにない場合は、1のカウントで追加します。
メモリが多いか、単語が比較的少ない場合は、すべてメモリに収まります。もしそうなら、あなたは私が以下に説明するヒープのことをすることができます。
メモリがいっぱいになった場合は、次のように、キーと値のペアを1行に1ワードずつテキストファイルに書き込むだけです。
word1, count
word2, count
次に、辞書をクリアして、単語を追加したり、単語数を増やしたりして、続けます。入力の最後に到達するまで、単語のブロックごとに必要に応じて繰り返します。
これで、単語とカウントのペアを含む巨大なテキストファイルができました。単語で並べ替えます。それを行う外部ソーティングツールはたくさんあります。頭に浮かぶのは、WindowsSORTユーティリティとGNUソートの2つです。どちらも、短い行の非常に大きなファイルを簡単に並べ替えることができます。
ファイルを単語で並べ替えると、次のようになります。
word1, count
word1, count
word2, count
word3, count
word3, count
word3, count
これで、ファイルを順番に調べて、単語の数を累積するだけです。単語の区切りごとに、以下に説明するように、ヒープに対するカウントを確認します。
このプロセス全体には時間がかかりますが、非常にうまく機能します。単語のブロックを並べ替えて個々のファイルに書き込むことで、速度を上げることができます。次に、入力の最後に到達したら、いくつかのブロックでN-wayマージを実行します。これは高速ですが、マージプログラムが見つからない限り、マージプログラムを作成する必要があります。私がこれを一度やっていたとしたら、私は簡単な解決策を選びます。頻繁に行う場合は、カスタムマージプログラムを作成するために時間を費やしていました。
頻度を計算した後...
ファイルに単語とその頻度が含まれていると仮定するk
と、最も頻度の高い単語を取得するだけで、O(n log k)になり、すべてのアイテムをメモリに保存する必要はありません。ヒープに必要なのはk個のアイテムのみです。
アイデア:
heap = new minheap();
for each item
// if you don't already have k items on the heap, add this one
if (heap.count < k)
heap.Add(item)
else if (item.frequency > heap.Peek().frequency)
{
// The new item's frequency is greater than the lowest frequency
// already on the heap. Remove the item from the heap
// and add the new item.
heap.RemoveRoot();
heap.Add(item);
}
すべてのアイテムを処理した後、ヒープにはk
最も頻度の高いアイテムが含まれます。