私はC ++に関する本でSTLコンテナー、特にSTLとそのコンテナーに関するセクションを読んでいます。今、私はそれらのそれぞれに固有の特性があることを理解し、それらのすべてを暗記するところです...しかし、まだ理解していないのは、それぞれがどのシナリオで使用されているかです。
説明は何ですか?サンプルコードをお勧めします。
私はC ++に関する本でSTLコンテナー、特にSTLとそのコンテナーに関するセクションを読んでいます。今、私はそれらのそれぞれに固有の特性があることを理解し、それらのすべてを暗記するところです...しかし、まだ理解していないのは、それぞれがどのシナリオで使用されているかです。
説明は何ですか?サンプルコードをお勧めします。
回答:
このチートシートは、さまざまなコンテナのかなり良い要約を提供します。
さまざまな使用シナリオで使用するガイドとして、下部のフローチャートを参照してください。
vector
空ではなく、空でなければなりません。stackoverflow.com/questions/10699265/...
unordered_map
and unordered_set
(およびそれらのマルチバリアント)があり、フローチャートには含まれていませんが、順序は気にせず、キーで要素を検索する必要がある場合に適しています。それらの検索は通常、O(log n)ではなくO(1)です。
以下は、私が作成したDavid Mooreのバージョン(上記を参照)に触発されたフローチャートで、新しい標準(C ++ 11)で(ほとんど)最新です。これは私の個人的な見解であり、疑う余地はありませんが、この議論にとって価値があると考えました。
vector (sorted)
は少し矛盾していると思います。これは別のタイプのコンテナではなく、同じですstd::vector
がソートされています。さらに重要なのstd::set
は、それがセットを反復する標準の動作である場合に、順序付き反復にforを使用できなかった理由がわかりません。確かに、答えがコンテナの谷の値に秩序立ってアクセスすることについて話している場合は[]
、それはsotedでしか行えませんstd::vector
。質問「順序が必要とされている」直後しかし、いずれの場合も、決定はなされるべきである
簡単な答え:std::vector
特に理由がない限り、すべてに使用します。
「ええ、std::vector
Xのためにここではうまくいかない」と思っているケースを見つけたら、Xを基準にしてください。
std::remove_if
は、ほとんどの場合、「反復中の削除」アプローチよりも優れています。
Scott MeyersによるEffective STLを見てください。STLの使い方を説明するのは得意です。
決定された/未決定の数のオブジェクトを保存し、何も削除しない場合は、ベクターが必要です。これはC配列のデフォルトの置き換えであり、C配列のように機能しますが、オーバーフローしません。そのサイズは、reserve()でも事前に設定できます。
不確定な数のオブジェクトを保存したいが、それらを追加して削除する場合は、おそらくリストが必要です...ベクトルとは異なり、後続の要素を移動せずに要素を削除できるためです。ただし、ベクトルより多くのメモリを必要とし、要素に順次アクセスすることはできません。
一連の要素を取り、それらの要素の一意の値のみを見つけたい場合は、それらをすべてセットに読み込むと、それが実行され、同様に並べ替えられます。
キーと値のペアがたくさんあり、それらをキーでソートしたい場合、マップは役に立ちますが、キーごとに1つの値しか保持できません。キーごとに複数の値が必要な場合は、マップの値としてベクター/リストを使用するか、マルチマップを使用できます。
これはSTLにはありませんが、STLのTR1アップデートに含まれています。キーで検索するキーと値のペアが多数あり、それらの順序を気にしない場合は、ハッシュを使いたい-これはtr1 :: unordered_mapです。私はそれをstdext :: hash_mapと呼ばれるVisual C ++ 7.1で使用しました。マップのO(log n)のルックアップの代わりにO(1)のルックアップがあります。
hash_map
はあまり良い実装ではないことを示唆しています。私は彼らが上手くやったと思いunordered_map
ます。
list
です。むしろそこに明白なエラー。
だけ簡単にこれまでに述べた重要な点は、ある(C配列が与えられるように)あなたが連続したメモリが必要な場合は、あなただけ使用することができvector
、array
またはstring
。
使用する array
コンパイル時にサイズがわかっている場合にします。
使用する string
汎用コンテナだけでなく、文字タイプだけを操作する必要があり、文字列が必要な場合にます。
vector
他のすべてのケースで使用(vector
とにかく、ほとんどの場合、コンテナーのデフォルトの選択です)。
これら3つすべてで、data()
メンバー関数を使用して、コンテナーの最初の要素へのポインターを取得できます。
それはすべて、何を保存したいか、そして何をコンテナで処理したいかに依存します。以下は、私が最もよく使用する傾向があるコンテナークラスのいくつかの(非常に網羅的ではない)例です。
vector
:含まれるオブジェクトごとのメモリオーバーヘッドがほとんどまたはまったくないコンパクトレイアウト。反復するのに効率的です。追加、挿入、および消去は、特に複雑なオブジェクトの場合、コストがかかる可能性があります。含まれているオブジェクトをインデックスで見つけるのは簡単です(例:myVector [10])。Cで配列を使用する場合に使用します。単純なオブジェクト(intなど)が多数ある場合に適しています。reserve()
コンテナに多くのオブジェクトを追加する前に使用することを忘れないでください。
list
:含まれるオブジェクトごとのメモリオーバーヘッドが小さい。反復するのに効率的です。追加、挿入、および消去は安価です。Cでリンクリストを使用した場所で使用します。
set
(およびmultiset
):含まれるオブジェクトごとの重要なメモリオーバーヘッド。そのコンテナに特定のオブジェクトが含まれているかどうかをすばやく確認する必要がある場合に使用するか、コンテナを効率的にマージします。
map
(そして multimap
):含まれるオブジェクトごとの重要なメモリオーバーヘッド。キーと値のペアを保存し、キーで値をすばやく検索する場所を使用します。
zdanによって提案されたチートシートのフローチャートは、より包括的なガイドを提供します。
私が学んだ1つの教訓は、次のとおりです。コンテナタイプをある晴れた日に変更すると大きな驚きが生じる可能性があるため、クラスでラップしてみてください。
class CollectionOfFoo {
Collection<Foo*> foos;
.. delegate methods specifically
}
事前にそれほどコストがかからず、誰かがこの構造体に対して操作xを行うたびに中断したい場合のデバッグ時間を節約できます。
ジョブに最適なデータ構造を選択することになる:
各データ構造はいくつかの操作を提供しますが、これは時間の複雑さを変化させる可能性があります。
O(1)、O(lg N)、O(N)など
基本的に、どの操作が最も多く行われるかを推測し、その操作がO(1)であるデータ構造を使用する必要があります。
シンプルですよね(-:
auto myIterator = whateverCollection.begin(); // <-- immune to changes of container type
typedef Collection<Foo*> CollectionOfFoo;
は十分では?
私はミカエル・パーソンの素晴らしいフローチャートを拡張しました。いくつかのコンテナーカテゴリ、配列コンテナー、およびいくつかのメモを追加しました。自分のコピーが必要な場合は、Google図面をご覧ください。土台を作ってくれてありがとう、ミカエル! C ++コンテナーピッカー
私はこの質問の重複としてマークされている別の質問でこれに答えました。しかし、標準のコンテナを選択する決定については、いくつかの優れた記事を参照するのが良いと思います。
@David Thornleyが答えたように、std :: vectorは、他に特別な必要がない場合の方法です。これは、C ++の作成者であるBjarne Stroustrupによる2014年のブログでのアドバイスです。
こちらが記事のリンクです https://isocpp.org/blog/2014/06/stroustrup-lists
それから引用して
そして、はい、私の推奨は、デフォルトでstd :: vectorを使用することです。
コメントの中で、ユーザー@NathanOliverは、より具体的な測定値を持つ別の優れたブログも提供しています。https://baptiste-wicht.com/posts/2012/12/cpp-benchmark-vector-list-deque.html。