STLコンフィギュレータとコンテナ、シーケンスコンテナと関連コンテナのまとめ
3956 ワード
STLには多くのコンテナタイプが定義されており、これらのタイプはC++で非常に実用的である.しかし、多くの人はなぜコンフィギュレーションとコンテナを呼ぶのか理解していません.以下にまとめます.シーケンスコンテナ:配列、vector、list、deque、stack、queue、heap、priority-queue.これらのタイプはvalueとして格納され,排出の論理的に線形構造である.ここで、stack、queueはコンフィギュレーションです.なぜコンテナではなくコンフィギュレーションと呼ぶのでしょうか.コンフィギュレーションの意味:ある物のインタフェースを修正して、別の風貌を形成して、adapter(コンフィギュレーション)と呼ばれます.これは私たちがソースコードに深く入り込んで一つ一つ分析する必要があります. vector:コードは連続したメモリとして実現され、動的拡張arrayと理解され、ランダムアクセスの特性を有する.ただし、頻繁なランダム挿入、削除には適していません. list:コードは双方向チェーンテーブル構造に実現され、頻繁にランダムに挿入、削除する操作に適している. deque:双方向操作キューで、コード実装が複雑です.1つのmapテーブル(STLではなくポインタ配列に似ている)を使用して、ブロックマッピングとして使用され、各アドレスは連続メモリを指し、各連続メモリサイズは同じである.deque内部は反復器startを介してfinishはそれぞれ最初のブロックと最後のブロックを指す. stack:スタックの特性は一方向操作であり、同じ入口、出口、FILOである.STLでは,dequeは双方向操作の機能を有するため,stackのセットを単独で実現する必要はない.Dequeに基づいて一端を閉じる操作だけでstackの特性を備えている.したがって、stackはadapterです. queue:キューの特性はFIFOで、一端は一端に出ます.同様にdequeに基づいて,一端のInputと他端のOutputをそれぞれ閉じることで,queueの特性を備えている.だからqueueもadapterです. heap:アルゴリズムとして提示されます.実装されたのはスタックソートで、vectorが含まれています. priority-queue:優先順位ソートを実現するためにheapが含まれています.
実際にqueue,stackの下位実装はdequeと同じであることがわかる.セグメントの定量的連続空間からなる.関連コンテナ:set、map、multiset、multimap、hashtable、hash_map、hash_set、hash_multiset、hash_multimap.これらのタイプはkey-valueとして格納され、keyは一意であり、容器内部にはkeyに基づいてRB-Tree、またはHashテーブルが構築される.keyによってvalueを位置決めします.
(1)mapとsetの挿入削除効率が他のシーケンスコンテナより高いのはなぜですか.
ほとんどの人は、関連コンテナにとってメモリコピーやメモリ移動を行う必要がないため、簡単だと言っています.そうだ、確かにそうだ.setコンテナ内のすべての要素はノードで格納され、ノード構造とチェーンテーブルの差が少なく、親ノードとサブノードを指します.構造図は次のようになります.
A
/\
B C
/\/\
D E F G
だから挿入するときは少しだけ変換して、ノードのポインタを新しいノードに向けるだけでいいのです.削除するときと同様に、少し変換して削除ノードへのポインタを他のノードに向けてもOKです.ここでのすべての操作はポインタを交換することであり、メモリの移動とは関係ありません.
(2)なぜinsertのたびに以前保存したiteratorが無効にならないのか.
iteratorここではノードを指すポインタに相当しますが、メモリは変わっていません.メモリを指すポインタはどのように失効しますか(もちろん削除された要素自体は失効しています).vectorに対して、削除と挿入のたびにポインタが無効になる可能性があります.push_を呼び出します.backが末尾に挿入されるのもそうです.内部データの連続保存を保証するために、iteratorが指すブロック内に削除と挿入中に他のメモリで上書きされたか、メモリが解放された可能性があるからです.場合でもpush_backの場合、コンテナの内部空間が足りない可能性があります.新しいメモリが必要です.以前のメモリを解放し、新しいメモリを申請し、既存のデータ要素を新しいメモリにコピーし、最後に挿入する必要がある要素を最後に置くだけで、以前のメモリポインタは自然に使用できません.特にfindなどのアルゴリズムと一緒に使用する場合は、期限切れのiteratorを使用しないことを覚えておきましょう.
したがって、set、map、listの場合、クライアントがエレメントinsert、delete操作を行う場合、操作前の反復器は、操作完了後も有効である(削除されたエレメントを除く).しかしvectorの場合、iteratorが期限切れにならないことを保証する必要があります.
(3)データ要素が多くなるとsetの挿入と検索速度はどうなるのか.
set/mapについては、STLの最下位のRB-Treeを呼び出して実現されています.RB-Treeについては、挿入、削除効率が高いことがわかります.logn.したがって、多くの要素のシーンにも適用されます.多くのファイルシステム、分散スケジューリングは、赤黒ツリーの検索プロパティを利用してインデックスまたはノード情報を格納します.
Set要素は変更できませんか?
Setは集合として格納される要素は1つの値しかなく,valueはkeyであり,keyもvalueである.一般的に、Setの値は読み取り専用であり、変更はできません.しかし必ずしもそうではない.SGI STLのバージョンに基づいて、具体的な分析が必要です.
筆者が使っているバージョンは、反復器で値を変更することができます.
コンパイルは正常に実行されました.その後setソースコードをめくることで、反復器の定義が異なるバージョンが見つかりました.iteratorをconstとして定義しているだけです.iteratorタイプのバージョンでは、Set要素の変更は許可されません.
だから、反復器を使うときは、読み取り専用と判断したらconst_を直接使うことをお勧めします.iterator、最も保険です.
実際にqueue,stackの下位実装はdequeと同じであることがわかる.セグメントの定量的連続空間からなる.
(1)mapとsetの挿入削除効率が他のシーケンスコンテナより高いのはなぜですか.
ほとんどの人は、関連コンテナにとってメモリコピーやメモリ移動を行う必要がないため、簡単だと言っています.そうだ、確かにそうだ.setコンテナ内のすべての要素はノードで格納され、ノード構造とチェーンテーブルの差が少なく、親ノードとサブノードを指します.構造図は次のようになります.
A
/\
B C
/\/\
D E F G
だから挿入するときは少しだけ変換して、ノードのポインタを新しいノードに向けるだけでいいのです.削除するときと同様に、少し変換して削除ノードへのポインタを他のノードに向けてもOKです.ここでのすべての操作はポインタを交換することであり、メモリの移動とは関係ありません.
(2)なぜinsertのたびに以前保存したiteratorが無効にならないのか.
iteratorここではノードを指すポインタに相当しますが、メモリは変わっていません.メモリを指すポインタはどのように失効しますか(もちろん削除された要素自体は失効しています).vectorに対して、削除と挿入のたびにポインタが無効になる可能性があります.push_を呼び出します.backが末尾に挿入されるのもそうです.内部データの連続保存を保証するために、iteratorが指すブロック内に削除と挿入中に他のメモリで上書きされたか、メモリが解放された可能性があるからです.場合でもpush_backの場合、コンテナの内部空間が足りない可能性があります.新しいメモリが必要です.以前のメモリを解放し、新しいメモリを申請し、既存のデータ要素を新しいメモリにコピーし、最後に挿入する必要がある要素を最後に置くだけで、以前のメモリポインタは自然に使用できません.特にfindなどのアルゴリズムと一緒に使用する場合は、期限切れのiteratorを使用しないことを覚えておきましょう.
したがって、set、map、listの場合、クライアントがエレメントinsert、delete操作を行う場合、操作前の反復器は、操作完了後も有効である(削除されたエレメントを除く).しかしvectorの場合、iteratorが期限切れにならないことを保証する必要があります.
(3)データ要素が多くなるとsetの挿入と検索速度はどうなるのか.
set/mapについては、STLの最下位のRB-Treeを呼び出して実現されています.RB-Treeについては、挿入、削除効率が高いことがわかります.logn.したがって、多くの要素のシーンにも適用されます.多くのファイルシステム、分散スケジューリングは、赤黒ツリーの検索プロパティを利用してインデックスまたはノード情報を格納します.
Set要素は変更できませんか?
Setは集合として格納される要素は1つの値しかなく,valueはkeyであり,keyもvalueである.一般的に、Setの値は読み取り専用であり、変更はできません.しかし必ずしもそうではない.SGI STLのバージョンに基づいて、具体的な分析が必要です.
筆者が使っているバージョンは、反復器で値を変更することができます.
ite1 = iset.find(23);
if (ite1 != iset.end())
{
cout << "23 found" <
コンパイルは正常に実行されました.その後setソースコードをめくることで、反復器の定義が異なるバージョンが見つかりました.iteratorをconstとして定義しているだけです.iteratorタイプのバージョンでは、Set要素の変更は許可されません.
template,
class _A = allocator<_k> >
class set {
public:
typedef set<_k _pr="" _a=""> _Myt;
typedef _K value_type;
struct _Kfn : public unary_function {
const _K& operator()(const value_type& _X) const
{return (_X); }
};
typedef _Pr value_compare;
typedef _K key_type;
typedef _Pr key_compare;
typedef _A allocator_type;
typedef _Tree<_k value_type="" _kfn="" _pr="" _a=""> _Imp;
typedef _Imp::size_type size_type;
typedef _Imp::difference_type difference_type;
typedef _Imp::reference reference;
typedef _Imp::const_reference const_reference;
typedef _Imp::iterator iterator;
typedef _Imp::const_iterator const_iterator;
};
だから、反復器を使うときは、読み取り専用と判断したらconst_を直接使うことをお勧めします.iterator、最も保険です.