- あなたは注文を気にしません
- あなたの鍵はすでにランダムです
- 1000万アイテム
短い答え
あなたのケースにはおそらくハッシュテーブルが最適でしょう。
スピード
ハッシュが定数の場合、ハッシュ テーブル ( std::unordered_map
) はO ( 1 ) になります。あなたの場合、ハッシュする必要さえないため、 O ( 1 ) が保持されます。ランダムな UUID の下位 32 ビットを使用するだけで十分です。ルックアップのコストは、1 つまたは 2 つのポインター インダイレクションに似ています。
二分木 ( std::map
) はO ( log 2 n ) になるため、1,000 万個のアイテムの場合、24 回の比較と 24 回の潜在的なキャッシュ ミスが発生します。n = 4,000の場合でも12 回の比較を使用するため、すぐにハッシュ テーブルよりも大幅に悪化します。
基数ツリーはO ( k ) になるため、最大k 個の比較とk 個の潜在的なキャッシュ ミスが発生します。最悪の場合、基数ツリーはハッシュ テーブルと同じくらい高速になります。最悪の場合 (256 方向のツリーの場合、 k = ある程度妥当な 16 であると仮定)、バイナリ ツリーよりも優れたパフォーマンスを発揮しますが、ハッシュ テーブルよりもはるかに劣ります。
したがって、速度が最優先される場合は、ハッシュ テーブルを使用してください。
オーバーヘッド
典型的なハッシュ テーブルは、いっぱいになった場合、項目ごとに約 1 ~ 3 個のポインターのオーバーヘッドがあります。いっぱいでない場合は、空のスロットごとに 1 ポインターのスペースを浪費することになるでしょう。非常にランダムなキーを持っているため、バイナリツリーよりも高速でありながら、ほぼ完全に保つことができるはずですが、可能な限り最大の速度を得るには、もちろん十分なヘッドルームを与える必要があります. 32 ビット マシンで 1,000 万項目の場合、テーブル全体で 38 ~ 114MiB のオーバーヘッドが予想されます。テーブルが半分埋まっている場合は、76 ~ 153 MiB が予想されます。
最も一般的な実装である赤黒ツリーには、std::map
アイテムごとに 3 つのポインター + 1 つのブール値があります。一部の実装では、ポインターの配置を利用して、bool をポインターの 1 つとマージします。実装とハッシュ テーブルがどれだけいっぱいかによっては、赤黒ツリーのオーバーヘッドがわずかに低くなる場合があります。114–153MiB を期待してください。
基数ツリーには、アイテムごとに 1 つのポインターと、空のスロットごとに 1 つのポインターがあります。残念ながら、このような大きなランダム キーを使用すると、ツリーの端に向かって空のスロットが非常に多くなり、おそらく上記のいずれよりも多くのメモリを使用することになると思います。kを小さくすると、このオーバーヘッドを下げることができますが、同様にパフォーマンスが低下します。
最小限のオーバーヘッドが重要な場合は、ハッシュ テーブルまたはバイナリ ツリーを使用します。優先度が高い場合は、完全なハッシュ テーブルを使用します。
std::unordered_map
サイズを変更するタイミングを制御できないため、完全に取得するのは難しいことに 注意してください。Boost Intrusiveunordered_map
には、それや他の多くのことを直接制御できる非常に優れた実装があります。