C++: 主要 STL コンテナのチートシート
概要
vector
, list
, map
, multiset
などなど多くの STL コンテナが存在しますが、データの追加/削除/参照など同じ名前のメソッドだったり微妙に違ったりしていて、時々忘れたり間違ったりしてしまいます。そこで本記事では、主要なコンテナの主要操作をまとめてみました。間違いや抜け、追加要望などありましたらコメント下さい。
基本的にデータの取り出し(pop, pop_back など)では値はリターンされないので忘れないように注意して下さい。
動的配列: vector
操作 | vector |
---|---|
追加 (指定した位置) | insert(v.begin(), 値) |
追加 (先頭) | - |
追加 (末尾) | push_back(値) |
参照 | v[インデックス] |
参照 (先頭) | front() |
参照 (末尾) | back() |
取り出し (先頭) | - |
取り出し (末尾) | pop_back() |
削除 (全ての要素) | clear() |
削除 (指定した値を持つ要素全て) | - |
削除 (指定したインデックス) | erase(v.begin() + インデックス) |
削除 (指定したイテレータ) | erase(itr) |
要素数ゼロ (空) の確認 | empty() |
要素数の取得 | size() |
サイズの変更 | resize(サイズ) |
vector型データ同士の比較
for文を使わなくても以下のようにif文一つでシンプルに書くことが出来ます。
if (v1 == v2) {
...
}
ヘッダファイル
#include <vector>
順序付集合: set / 多重集合: multiset
set
は平衡二分探索木 (self-balancing binary search tree) と呼ばれるデータ構造で実現されており、O(long N)
でデータへのアクセスと追加、削除が可能です。また、重複したデータは捨てられてユニークなデータだけの集合になります。また、データは自動的に昇順ソートされて保存されており、最小値 (begin()
)と最大値(rbegin()
)を O(1)
で取得可能です。
似たデータ構造でmultiset
があります。multiset
のset
との差分はデータの重複が可能という点です。使い勝手はどちらも同じです。重複を許可する場合はmultiset
、重複したデータを除去したい場合はset
という使い分けです。
なお、イテレータで各データを更新は出来ないため、更新したい場合には一度削除して再度挿入操作が必要です。
操作 | set / multiset |
---|---|
追加 | insert(値) |
参照 (最小値) | begin() |
参照 (最大値) | rbegin() |
検索 (値): イテレータ | find(値) |
検索 (値): 存在する個数 | count(値) |
削除 (全ての要素) | clear() |
削除 (指定した値) | erase(値) |
削除 (指定したイテレータ) | erase(itr) |
要素数ゼロ (空) の確認 | empty() |
要素数の取得 | size() |
各要素を順番に確認していく
イテレータをインクリメントして順番に検索することが可能です。
for (auto itr = st.begin(); itr != st.end(); itr++)
cout << *itr << endl;
初期化
vector型のデータなどをset/multiset型の変数に代入(初期化)する時には以下のようにfor文を使わずにシンプルに書くことが可能です。
set<int> st(v.begin(), v.end());
lower_bound が使える
set
もmultiset
もlower_bound
を提供してくれているので、以下のようにバイナリサーチで引数で指定した値以上になる最小のイテレータを探してくれます。
auto itr = st.lower_bound(x);
auto itr = ms.lower_bound(x);
ヘッダファイル
#include <set> // set, multiset
ヒープ: priority_queue
内部的には vector
を用いて、ヒープを構築します。デフォルトでは、値が大きいものがキューの先頭に来ます。priority_queue
は、pop
を利用して先頭のノードを取り出すことは可能ですが、値を指定してどこかのノードの削除することは出来ません。そのため、値を削除したい場合には代わりにmultiset
を使います。また、ノードの値を変更することも出来ません。
操作 | priority_queue |
---|---|
追加 | push(値) |
参照 (最大値) | top() |
取り出し (先頭) | pop() |
要素数ゼロ (空) の確認 | empty() |
要素数の取得 | size() |
値が小さいものがツリーの上位(先頭)に来て欲しい場合
変数宣言時にstd::greater<int>
を指定することで並び順を昇順(親ノードの値が必ず子ノードの値よりも小さい)にすることが可能です。
std::priority_queue<int, std::vector<int>, std::greater<int>> pq;
ヘッダファイル
#include <queue> // priority_queue
平衡二分木: map
set
と同じように平衡二分木で実現され、辞書のように対応するキーとデータをセットにして保存します。なお、平衡二分木のためキーの昇順で保存されており、キーは重複を許しません。
ハッシュテーブルのような使い方が出来ますが、実際には平衡二分木で実装されているため、O(1)
でのデータアクセスではなくO(log N)
かかります。辞書として使う場合には、後述のunordered_map
を使う方が良いです。
操作 | map |
---|---|
追加 | mp[キー] = 値 |
参照 (キー) | mp[キー] |
参照 (最小値) | begin() |
参照 (最大値) | rbegin() |
検索 (値): イテレータ | find(値) |
検索 (値): 存在する個数 | count(値) ※実質 1 or 0のみ返る |
検索 (指定した値以上の最小値のノード): イテレータ | lower_bound(キー) |
検索 (指定した値より大きいの最小値のノード): イテレータ | upper_bound(キー) |
削除 (全ての要素) | clear() |
削除 (指定したキーを持つノード) | erase(キー) |
削除 (指定したイテレータ) | erase(itr) |
要素数ゼロ (空) の確認 | empty() |
要素数の取得 | size() |
サイズの変更 | - |
ヘッダファイル
#include <map>
スタック: stack
操作 | stack |
---|---|
追加 (指定した位置) | - |
追加 (先頭) | - |
追加 (末尾) | push(値) |
参照 (先頭) | - |
参照 (末尾) | top() |
取り出し (先頭) | - |
取り出し (末尾) | pop() |
削除 (全ての要素) | - |
削除 (指定した値を持つ要素全て) | - |
削除 (指定したインデックス) | - |
削除 (指定したイテレータ) | - |
要素数ゼロ (空) の確認 | empty() |
要素数の取得 | size() |
サイズの変更 | - |
ヘッダファイル
#include <stack>
キュー / 両端キュー: deque / 双方向リスト
deque
と通常のqueue
の違いは、deque
は先頭にもO(1)
でデータの追加が可能で任意のデータの削除も可能です。また、deque
はバイナリサーチも可能であるため、単調増加なキューイングされたデータに対してバイナリサーチを行う場合にも有効です。
操作 | queue | deque | list |
---|---|---|---|
追加 (指定した位置) | - | - | insert(itr, 値) |
追加 (先頭) | - | push_front(値) | push_front(値) |
追加 (末尾) | push(値) | push_back(値) | push_back(値) |
参照 (先頭) | front() | front() | front() |
参照 (末尾) | back() | back() | back() |
取り出し (先頭) | pop() | pop_front() | pop_front() |
取り出し (末尾) | - | pop_back() | pop_back() |
削除 (全ての要素) | - | clear() | clear() |
削除 (指定した値を持つ要素全て) | - | - | remove(値) |
削除 (指定したインデックス) | - | erase(itr + インデックス) | erase(itr + インデックス) |
削除 (指定したイテレータ) | - | erase(itr) | erase(itr) |
要素数ゼロ (空) の確認 | empty() | empty() | - |
要素数の取得 | size() | size() | size() |
サイズの変更 | - | resize(サイズ) | resize(サイズ) |
リスト型のデータ削除時には注意が必要なので合わせて[C++] 双方向リスト (list) の要素探索と削除操作時の注意を参照してください。
ヘッダファイル
#include <queue> // queue
#include <deque> // deque
#include <list> // list
ハッシュ (連想配列)
set
, map
と同じ機能を持ち、内部のデータ構造がハッシュになっているのが unordered_set
と unordered_map
です。O(1)
でデータの参照追加などを行う場合にはこれを利用します。
操作 | unordered_map | unordered_set |
---|---|---|
追加 | mp[キー] = 値 | insert(値) |
参照 (キー) | mp[キー] | <- |
検索 (値): イテレータ | find(値) | <- |
検索 (値): 存在する個数 | count(値) | <- |
削除 (全ての要素) | clear() | <- |
削除 (指定したキーを持つノード) | erase(キー) | <- |
削除 (指定したイテレータ) | erase(itr) | <- |
要素数ゼロ (空) の確認 | empty() | <- |
要素数の取得 | size() | <- |
ヘッダファイル
#include <unordered_map> // unordered_map
#include <unordered_set> // unordered_set
bitset
ビットデータ配列のようなものを扱うときにbitset
を利用します。各要素は0もしくは1のみを取ります。
std::bitset<8> bset(0xff);
bset.set(1)
bset.set(2, false)
bset[0] = true;
操作 | stack |
---|---|
指定したビットを反転 | flip(対象ビット) |
全ビット反転 | flip() |
ビットが1の数をカウント | count() |
ビットをセット | set(対象ビット) |
ビットをクリア | set(対象ビット, false) |
ヘッダファイル
#include <bitset>
Discussion