web-dev-qa-db-ja.com

ベクターまたはマップ、どちらを使用しますか?

コンテナで予想される要素の数が比較的少ない場合は、std::vector の代わりに std::mapコンテナを使用するのはルックアップのみであり、反復ではありません。

この背後にある本当の理由は何ですか?

明らかに、mapのルックアップパフォーマンスはベクターのルックアップパフォーマンスよりも悪くなることはありません(ナノ秒/マイクロ秒の場合もあります)ので、メモリ使用量と関係がありますか?

仮想アドレス空間の断片化において、ベクターはマップよりも優れているか悪いですか?

Visual Studioに付属のSTLライブラリ(つまり、Microsoftの実装)を使用していますが、他の実装との違いはありますか?

62
Naveen

map<A, B>vector<pair<A, B> >を比較していると思います。

まず、非常に小さなベクター内のアイテムを見つけることは、ベクター内のすべてのメモリが常に連続しているため(コンピューターのキャッシュなどでより適切に再生されるため)、マップ内の同じものよりも簡単に高速になります。ベクトル内で何かを見つけるために必要な比較の数は、マップの場合とほぼ同じです。マップ内の要素を見つけるのに必要な操作は、非常に大きなコンテナーの制限内で少なくなります。

マップがベクトルよりも高速になるポイントは、実装、プロセッサ、マップ内のデータ、およびプロセッサのキャッシュ内のメモリなどの微妙な事項によって異なります。通常、マップが高速になるポイントは約5〜30要素です。

別の方法は、ハッシュコンテナを使用することです。多くの場合、hash_mapまたはunordered_mapという名前です。 hash_mapという名前のクラスは、公式の標準の一部ではありません(また、いくつかのバリエーションがあります)。 std::tr1::unordered_mapです。ハッシュマップは、多くの要素が含まれているかどうかに関係なく、通常のルックアップマップよりも高速ですが、実際に高速であるかどうかは、キーの種類、ハッシュ方法、処理する値、および方法によって異なりますキーはstd :: mapで比較されます。 std :: mapのような特定の順序で物事を保持しませんが、あなたはそれを気にしないと言いました。特にキーが整数またはポインターの場合、ハッシュマップは非常に高速であるため、ハッシュマップをお勧めします。

63
Doug

通常、マップはバイナリ検索ツリーとして実装され、バイナリツリーを歩くと常にオーバーヘッドが発生します(比較の実行、リンクの移動など)。ベクトルは基本的に単なる配列です。非常に少量のデータ(おそらく8または12要素)の場合、バイナリ検索ツリーをたどるよりも、配列に対して線形検索を行う方が速い場合があります。

いくつかのタイミングを自分で実行して、損益分岐点がどこにあるかを確認できます。4つの要素、8、16などの要素を検索して、STLの特定の実装のスイートスポットを見つけます。

マップにはヒープ全体に小さな割り当てがたくさんある傾向がありますが、ベクトルは連続しているため、ベクトルのキャッシュヒット率は、すべての要素を前から後ろに反復する場合に時々少し良くなります。

28
Crashworks

「デフォルトでは、コンテナが必要な場合はベクターを使用してください」-Bjarne Stroustrup。

そうでなければ、この小さなフローチャートは非常に良い助けになると思います:

http://homepages.e3.net.nz/~djm/cppcontainers.html

22

一度にすべての挿入を行い、その後多くのルックアップを行う場合、ベクトルを使用して、挿入中に並べ替えることができます。次に、lower_boundを使用してクイックルックアップを実行します。多数のアイテムであっても、マップを使用するよりも高速です。

4
Mark Ransom

これを見るもう1つの方法は、小さなコンテナについて話している場合、どちらも検索に非常に長い時間はかかりません。非常にタイトなループでこのコンテナを検索しない限り、時間の差はおそらく無視できるでしょう。

その場合、どのコンテナがあなたのやりたいことにより近いかを探します。特定の値を探している場合、マップの組み込みのfind()メソッドは、forループを作成してベクトルを反復処理するよりもはるかに簡単です(使用するのが簡単です)。

おそらく、あちこちで数ナノ秒以上の価値があります。

3
teeks99

まず最初にデータに適合するコンテナを使用する必要があると思います。 std :: vectorは、Cまたはpre-STL C++で配列を使用する状況で使用されます。高速の一定時間検索で値を格納するために、連続したメモリブロックが必要です。キーを値にマップするには、std :: mapを使用する必要があります。ここでの主なオーバーラップは、size_tをキーとするベクトルとマップです。その場合、2つの懸念があります。インデックスは連続的ですか?そうでない場合、おそらくベクトルでメモリを浪費することになります。第二に、検索時間はどれくらいですか?ベクトルには一定の時間ルックアップがありますが、std :: mapは通常RBツリーとして実装され、O(log n)ルックアップ時間を持ち、ハッシュマップ(TR1 unordered_mapなど)の複雑さも通常はより低くなります。インデックス(またはそのハッシュ)は、複数の値を含むことができるバケットにマッピングされるためです。

ペアを持つベクターを目指していた場合:ベクターの要素を見つけて、findを使用して要素を見つけることができます。しかし、これはバイナリ検索であり、実際にはstd :: mapと同じくらい高速です。

とにかく、明白な方法でデータをモデル化してみてください。時期尚早の最適化は、多くの場合、あまり役に立ちません。

3
danieldk

基本的に、マップは検索に使用されます。

ただし、ルックアップであってもstd::vectorの代わりにstd::mapを使用できる場合があります。

キーと値のペアの要素が非常に少なくなる場合は、std::vector<std::pair<x,y>>でもキーを使用して反復検索を行うことができます。

これは、特に文字列のハッシュや、データをヒープに格納するようなマップ内の他の操作の場合、ハッシュに時間がかかるためです。

検索する必要のある要素がさらにある場合や、所有する要素のリストを頻繁に検索する場合にのみ、std :: mapでより良い違いが表示されます。

0
fury.slay