いつベクター/リストを使用する必要がありますか?


17

リストをいつ使用するかは理解できますが、ビデオゲームでリストを使用するよりもベクターを使用する方がよい場合はわかりません。高速ランダムアクセスを使用する方がよい場合

(そして、ポインタを削除/追加するだけなので、リストに挿入/削除する方が速い理由を理解していますが、それでも対応するアイテムを見つける必要があります...)


これにベクタータグを再追加しました-リストが有効なタグである場合、ベクターも同様です。
キロタン

vectorは、std :: vectorではなく数学的なベクトルを意味するために使用されたため、おそらく削除されました。

1
どのようにnixの両方とプットについてcontainer
-deft_code

@カイロタン:ジョーが言ったとおりです。この質問はベクターに関するものでしたが、ベクタータグには属していませんでした。
-doppelgreener

1
あいまいなタグは削除しますか?それは私にとって間違った決定のように聞こえます-あなたの検索が十分ではないよりも多くの情報を見つけ出すことをお勧めします。不要な結果をスキップすることは、同義語を見つけるためにブレーンストーミングするよりも簡単です。
キロタン

回答:


29

私の経験則、と私は確信してこの上の議論があるだろうよ、することです決してリストを使用しない(あなたは非常に、非常に頻繁に大規模なリストの途中から物事を削除する必要がない場合)。

コンテナ内のすべての要素を連続したメモリに置くことで得られる速度(したがって、よりキャッシュに優しい)は、ベクトルの追加/削除/サイズ変更の追加コストを相殺する価値があります。

編集:少しだけ明確にするために、言うまでもなく、特定のニーズに関連するデータセットを備えたプラットフォームで、「高速な」質問をテストする必要があることは言うまでもありません。要素のコレクションが必要な場合は、正当な理由がない限り、ベクター(またはdeque、ほとんど同じ)を使用します。


1
特定の要素にアクセスする必要がなく、それらすべてを読むだけで、要素を頻繁に追加および削除する必要がある場合、ニーズに大きく依存すると思います。リストはより良いソリューションです。
フレデリックインボー

11
@Frédérick:それは標準のC ++の知恵ですが、ほとんど常に間違っています。ベクターは、特にポインターのベクター(ほとんど常にゲーム用)を扱う場合、中央からものを削除するのが非常に高速です-それは線形時間ですが、アイテムごとの非常に小さなオーバーヘッドです。また、ベクトルを順次処理する方がはるかに高速です。

1
どのような構造になっているのか正確にはわかりません-この種の最適化には、明確に何かを言うための具体的な例が必要です。たとえば、ユースケースに対する私の最初の反応は、順不同のセットです。これにより、挿入、削除、ルックアップが同等に高速になります。私の経験では、セットはエディターのオブジェクトに最適です。しかし、エディターにはより多くのリアルタイムパフォーマンス要件があります。たとえば、「削除」ボタンの押下に応答する時間が1/20秒または1/2秒で10%の場合-このレベルの最適化また、ほとんど適用されません。

1
@FrédérickImbeault Modifiedは、Add \ Removeで問題を引き起こす問題ではありません。ベクトルの連続性を保つために、add \ removedポイントからベクトルの終わりまでがコピーされます。要素の順序が重要でない場合は、削除された要素を最後の要素と交換し、削除する要素をポップして、追加するために最後に追加することができます。
ストーンメタル

4
確かに、ベクター内の要素のアドレスを取得し、それを保存することは安全ではありません。しかし、一般的に言えば、あなたはそれをすることはほとんどなく、代わりに要素のポインターのベクトルを持つことを好み、そのポインターをコピーします(または同様のもの)。
テトラッド

8

データ構造の中央を変更することによりイテレータの無効化が問題を引き起こす場合、または要素をソートしたままにして、中間コレクションをすばやく削除するためのスワップとポップトリックが機能せず、大きな中間コレクション削除の数。

Dequeの使用を検討することもできます。これはベクターと同様のパフォーマンス特性を備えていますが、ベクターが連続したメモリを必要とせず、少し柔軟性があります。


両端キューに言及する唯一の人物である+1-両端での高速な挿入/削除により、連続したメモリとベクターのルックアップ速度の利点が得られます。

5

あなたの選択はあなたのニーズを反映すべきです。ベクトルのすべての要素はメモリ内で連続しており、リストには次/前の要素へのポインタがあるため、それぞれに利点/欠点があります。

リスト:

  • 各要素は、前の要素と次の要素を指すために2つの整数を必要とするため、最も一般的には、リスト内の各要素に対して8バイト多くなります
  • 挿入は時間的に線形です:O(n)
  • 削除は一定の操作です:O(1)
  • x要素へのアクセスは時間的に線形です:O(n)

ベクトル:

  • 必要なメモリが少ない(他の要素へのポインタがなく、単純な数学アルゴリズムです)
  • 削除は時間的に線形です:O(n)
  • x要素へのアクセスは定数です:O(1)(要素はメモリ内で連続しているため、単純な数学演算vectorPtr +(x * bytesOfTheType))
  • 挿入は線形時間にすることができますが、最も一般的には、定数操作です:O(1)(これは、配列内のベクトルが、配列がいっぱいのときに常に容量の2倍を予約するため、配列のコピーが頻繁に行われないためです)

したがって、プログラムは頻繁に要素を追加および削除する必要があるが、前に他の要素を必要とせずに特定の要素にアクセスしない(またはめったにアクセスしない)場合にリストが優れています。アクセス時間を短縮するためにベクトルを使用する必要がありますが、要素を削除または追加する必要がある場合は効率が低下します。

stackoverflowでこの投稿を確認してください。回答に応じて特定のコンテナに移動する、ニーズに関する基本的な質問を含む本当に素晴らしいグラフが表示されます。

/programming/366432/extending-stdlist


3
このグラフは、「ポインターを格納していて、1000個未満ですか?いいえ->ベクター」ノードから始める必要があります。

はい多分あなたは正しいです、私はそれが分析されるべきである保存されたタイプも考慮しませんでした。
フレデリックインボー

2

通常、リストは、追加操作や削除操作が多いキューなどの構造に使用されます。例:更新する必要のあるエンティティの絶えず変化するリスト。リスト自体には画面上のエンティティのみが含まれるため、頻繁に変更されます。

ベクター(または配列)は、それほど変化しないコレクションや、コレクション内の個々のアイテムへの高速アクセスが必要なコレクションに適しています。例:特定のインデックスでタイルを検索する必要があるタイルマップ。

Tetradsの意見は正しいかもしれませんが、使用されるプログラミング言語に依存します。質問c++にタグを付けたようですが、言語固有ではない回答をしようとしました。


まあ、私もCを入れたかもしれませんが、Cにはそのようなコンテナはありませんが、それは考えることです:CにはSTLのようなテーブルがありますか?
jokoon

私は過去にglib(library.gnome.org/devel/glib)を使用しました。これは、Cの標準データ構造の多くを実装します。安定しています。

0

コンソールゲームでは、std :: listを使用することはありません。

  1. 新しいアイテムを追加するたびにメモリ割り当てを行います。メモリの割り当てが遅い。
  2. ポインタがいっぱいです。ポインターが悪い。ポインターはキャッシュミスです。キャッシュミスは悪いです。

std :: vectorでさえ、コンソールで好意を失っています:

  1. たとえば、すべてのオブジェクトの位置だけを気にすることがよくあります。たとえば、オブジェクトを互いに衝突させたい場合などです。この場合、オブジェクトの色は気にしません。したがって、キャッシュを汚染しないように、メモリ内のすべての位置を連続させ、色を遠く離れた場所に配置する必要があります。ただし、std :: vectorでは、各オブジェクトのすべてを連続したメモリチャンクに格納する必要があります(位置と色など)。したがって、位置のみを読み取る作業を行う場合は、すべての色もキャッシュに読み込む必要があります。使用しない場合。これは無駄です。

5
@bmcnett "[] ..しかし、std :: vectorでは、各オブジェクトのすべてを連続したメモリチャンクに保存する必要があります"-コンテナの問題ではなく、データレイアウトの問題です。 std :: vector:を使用した連続したメモリチャンクでstruct point{float x, y, z, w}; std::vector<point> positions;
Maik Semder

私の学校はこれを愛するつもりです:)
jokoon

2
-1。この答えはリストに何も追加しないので、すでにここで説明したベクターの議論と、ベクターがキャッシュを汚染するという主張は間違っている、とMaikは言います。

あなたは私の主張を誤解した。すべてのコンテナ std :: vectorがキャッシュを汚染することで特に有罪になるとは言いませんでした。すべてのコンテナ、そして実際には配列でさえ、ほぼ同様に有罪です。std :: vectorは、C ++オブジェクト自体が支持を失っているため、支持を失っています。C ++では、各オブジェクトのデータはメモリ内で連続している必要があります。上記のようにstd :: vector <position>を使用するなどして、C ++オブジェクトを回避することで回避できます。
bmcnett

3
例外pointはC ++オブジェクトです(そのままstd::vector、のようなものfloat)。私はあなたが描いている区別を知っていますが、あなたはそれを説明するのが悪い仕事をしています。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.