サーチ…
備考
std::map
またはstd::multimap
のいずれかを使用するには、ヘッダーファイル<map>
を含める必要があります。std::map
とstd::multimap
は、キーの昇順に従ってソートされた要素を保持します。std::multimap
場合、同じキーの値に対してソートは行われません。基本的な違い
std::map
とstd::multimap
ことあるstd::map
1が同じキーの重複値を許可しないstd::multimap
ありません。マップはバイナリ検索ツリーとして実装されています。したがって、
search()
、insert()
、erase()
はΘ(log n)時間を平均します。一定の時間操作を行うには、std::unordered_map
使用します。size()
およびempty()
関数はΘ(1)時間の複雑さを持ち、ノードの数はこれらの関数が呼び出されるたびにツリーを通らないようにキャッシュされます。
要素へのアクセス
std::map
は(key, value)
ペアを入力として受け取ります。
次のstd::map
初期化の例を考えてみましょう。
std::map < std::string, int > ranking { std::make_pair("stackoverflow", 2),
std::make_pair("docs-beta", 1) };
std::map
では、要素を次のように挿入できます。
ranking["stackoverflow"]=2;
ranking["docs-beta"]=1;
上記の例では、キーのstackoverflow
がすでに存在する場合、その値は2に更新されます。まだ存在しない場合は、新しいエントリが作成されます。
std::map
では、キーにインデックスを付けることによって、要素に直接アクセスできます。
std::cout << ranking[ "stackoverflow" ] << std::endl;
マップ上でoperator[]
を使用すると、実際には照会されたキーとともに新しい値がマップに挿入されます。これは、キーがすでにマップに格納されていても、 const std::map
で使用できないことを意味します。この挿入を防止するには、要素が存在するかどうか(たとえば、 find()
使用at()
)、またはat()
を以下のように使用するかどうかを確認します。
std::map
要素は、 at()
アクセスできます。
std::cout << ranking.at("stackoverflow") << std::endl;
コンテナに要求された要素が含まれていない場合、 at()
はstd::out_of_range
例外をスローします。
std::map
とstd::multimap
両方のコンテナでは、イテレータを使用して要素にアクセスできます。
// Example using begin()
std::multimap < int, std::string > mmp { std::make_pair(2, "stackoverflow"),
std::make_pair(1, "docs-beta"),
std::make_pair(2, "stackexchange") };
auto it = mmp.begin();
std::cout << it->first << " : " << it->second << std::endl; // Output: "1 : docs-beta"
it++;
std::cout << it->first << " : " << it->second << std::endl; // Output: "2 : stackoverflow"
it++;
std::cout << it->first << " : " << it->second << std::endl; // Output: "2 : stackexchange"
// Example using rbegin()
std::map < int, std::string > mp { std::make_pair(2, "stackoverflow"),
std::make_pair(1, "docs-beta"),
std::make_pair(2, "stackexchange") };
auto it2 = mp.rbegin();
std::cout << it2->first << " : " << it2->second << std::endl; // Output: "2 : stackoverflow"
it2++;
std::cout << it2->first << " : " << it2->second << std::endl; // Output: "1 : docs-beta"
std :: mapまたはstd :: multimapの初期化
std::map
とstd::multimap
両方は、コンマで区切られたキーと値のペアを提供することで初期化できます。キーと値のペアは、 {key, value}
いずれかによって提供されるか、 std::make_pair(key, value)
によって明示的に作成されstd::make_pair(key, value)
。 std::map
は重複キーを許さず、カンマ演算子は右から左へ実行するので、右のペアは左の同じキーを持つペアで上書きされます。
std::multimap < int, std::string > mmp { std::make_pair(2, "stackoverflow"),
std::make_pair(1, "docs-beta"),
std::make_pair(2, "stackexchange") };
// 1 docs-beta
// 2 stackoverflow
// 2 stackexchange
std::map < int, std::string > mp { std::make_pair(2, "stackoverflow"),
std::make_pair(1, "docs-beta"),
std::make_pair(2, "stackexchange") };
// 1 docs-beta
// 2 stackoverflow
どちらもイテレータで初期化できます。
// From std::map or std::multimap iterator
std::multimap< int , int > mmp{ {1, 2}, {3, 4}, {6, 5}, {8, 9}, {6, 8}, {3, 4},
{6, 7} };
// {1, 2}, {3, 4}, {3, 4}, {6, 5}, {6, 8}, {6, 7}, {8, 9}
auto it = mmp.begin();
std::advance(it,3); //moved cursor on first {6, 5}
std::map< int, int > mp(it, mmp.end()); // {6, 5}, {8, 9}
//From std::pair array
std::pair< int, int > arr[10];
arr[0] = {1, 3};
arr[1] = {1, 5};
arr[2] = {2, 5};
arr[3] = {0, 1};
std::map< int, int > mp(arr,arr+4); //{0 , 1}, {1, 3}, {2, 5}
//From std::vector of std::pair
std::vector< std::pair<int, int> > v{ {1, 5}, {5, 1}, {3, 6}, {3, 2} };
std::multimap< int, int > mp(v.begin(), v.end());
// {1, 5}, {3, 6}, {3, 2}, {5, 1}
要素の削除
すべての要素を削除する:
std::multimap< int , int > mmp{ {1, 2}, {3, 4}, {6, 5}, {8, 9}, {3, 4}, {6, 7} };
mmp.clear(); //empty multimap
イテレータの助けを借りてどこかから要素を削除する:
std::multimap< int , int > mmp{ {1, 2}, {3, 4}, {6, 5}, {8, 9}, {3, 4}, {6, 7} };
// {1, 2}, {3, 4}, {3, 4}, {6, 5}, {6, 7}, {8, 9}
auto it = mmp.begin();
std::advance(it,3); // moved cursor on first {6, 5}
mmp.erase(it); // {1, 2}, {3, 4}, {3, 4}, {6, 7}, {8, 9}
範囲内のすべての要素を削除する:
std::multimap< int , int > mmp{ {1, 2}, {3, 4}, {6, 5}, {8, 9}, {3, 4}, {6, 7} };
// {1, 2}, {3, 4}, {3, 4}, {6, 5}, {6, 7}, {8, 9}
auto it = mmp.begin();
auto it2 = it;
it++; //moved first cursor on first {3, 4}
std::advance(it2,3); //moved second cursor on first {6, 5}
mmp.erase(it,it2); // {1, 2}, {6, 5}, {6, 7}, {8, 9}
指定された値を持つすべての要素をキーとして削除する:
std::multimap< int , int > mmp{ {1, 2}, {3, 4}, {6, 5}, {8, 9}, {3, 4}, {6, 7} };
// {1, 2}, {3, 4}, {3, 4}, {6, 5}, {6, 7}, {8, 9}
mmp.erase(6); // {1, 2}, {3, 4}, {3, 4}, {8, 9}
述語pred
を満たす要素を削除する:
std::map<int,int> m;
auto it = m.begin();
while (it != m.end())
{
if (pred(*it))
it = m.erase(it);
else
++it;
}
要素を挿入する
要素がstd::map
まだ存在しない場合にのみ、要素をstd::map
挿入することができます。例えば、
std::map< std::string, size_t > fruits_count;
キーと値のペアは、
insert()
メンバー関数を介してstd::map
挿入されます。それは引数としてpair
を必要とします:fruits_count.insert({"grapes", 20}); fruits_count.insert(make_pair("orange", 30)); fruits_count.insert(pair<std::string, size_t>("banana", 40)); fruits_count.insert(map<std::string, size_t>::value_type("cherry", 50));
insert()
関数は、イテレータとbool
値からなるpair
返します。- 挿入が成功した場合、イテレータは新しく挿入された要素を指し、
bool
値はtrue
です。 - 同じ
key
持つ要素が既に存在する場合、挿入は失敗します。それが起こると、反復子は競合を引き起こす要素を指し、bool
は値がfalse
です。
挿入操作と検索操作を組み合わせるには、次のメソッドを使用できます。
auto success = fruits_count.insert({"grapes", 20}); if (!success.second) { // we already have 'grapes' in the map success.first->second += 20; // access the iterator to update the value }
- 挿入が成功した場合、イテレータは新しく挿入された要素を指し、
便宜上、
std::map
コンテナは、std::map
内の要素にアクセスする添え字演算子を提供し、存在しない場合は新しいものを挿入します。fruits_count["apple"] = 10;
簡単ですが、要素がすでに存在するかどうかをユーザーが確認するのを防ぎます。要素がない場合、
std::map::operator[]
暗黙的にそれを作成し、指定された値で上書きする前にデフォルトのコンストラクタで初期化します。
insert()
は、ペアのブレースリストを使用して複数の要素を一度に追加するために使用できます。このバージョンのinsert()はvoidを返します:fruits_count.insert({{"apricot", 1}, {"jackfruit", 1}, {"lime", 1}, {"mango", 7}});
insert()
は、value_type
値の開始と終了を示すイテレータを使用して要素を追加するためにも使用できます。std::map< std::string, size_t > fruit_list{ {"lemon", 0}, {"olive", 0}, {"plum", 0}}; fruits_count.insert(fruit_list.begin(), fruit_list.end());
例:
std::map<std::string, size_t> fruits_count;
std::string fruit;
while(std::cin >> fruit){
// insert an element with 'fruit' as key and '1' as value
// (if the key is already stored in fruits_count, insert does nothing)
auto ret = fruits_count.insert({fruit, 1});
if(!ret.second){ // 'fruit' is already in the map
++ret.first->second; // increment the counter
}
}
std::map
はツリーとして実装されているため、挿入操作の時間の複雑さはO(log n)です。
pair
はmake_pair()
とemplace()
を使って明示的に構築することができます:
std::map< std::string , int > runs;
runs.emplace("Babe Ruth", 714);
runs.insert(make_pair("Barry Bonds", 762));
新しい要素がどこに挿入されるか分かっているなら、 emplace_hint()
を使ってイテレータのhint
を指定することができます。 hint
直前に新しい要素を挿入できる場合、挿入は一定の時間内に実行できます。それ以外の場合は、 emplace()
と同じように動作します。
std::map< std::string , int > runs;
auto it = runs.emplace("Barry Bonds", 762); // get iterator to the inserted element
// the next element will be before "Barry Bonds", so it is inserted before 'it'
runs.emplace_hint(it, "Babe Ruth", 714);
std :: mapまたはstd :: multimapを繰り返し処理する
std::map
またはstd::multimap
は次の方法でトラバースできます:
std::multimap< int , int > mmp{ {1, 2}, {3, 4}, {6, 5}, {8, 9}, {3, 4}, {6, 7} };
//Range based loop - since C++11
for(const auto &x: mmp)
std::cout<< x.first <<":"<< x.second << std::endl;
//Forward iterator for loop: it would loop through first element to last element
//it will be a std::map< int, int >::iterator
for (auto it = mmp.begin(); it != mmp.end(); ++it)
std::cout<< it->first <<":"<< it->second << std::endl; //Do something with iterator
//Backward iterator for loop: it would loop through last element to first element
//it will be a std::map< int, int >::reverse_iterator
for (auto it = mmp.rbegin(); it != mmp.rend(); ++it)
std::cout<< it->first <<" "<< it->second << std::endl; //Do something with iterator
std::map
またはstd::multimap
を繰り返し処理する間は、無用な暗黙的な変換を避けるためにauto
使用することをおstd::multimap
します(詳細はSO答えを参照してください)。
std :: mapまたはstd :: multimapで検索する
std::map
またはstd::multimap
でキーを検索する方法はいくつかあります。
キーの最初の出現のイテレータを取得するには、
find()
関数を使用できます。キーが存在しない場合はend()
返します。std::multimap< int , int > mmp{ {1, 2}, {3, 4}, {6, 5}, {8, 9}, {3, 4}, {6, 7} }; auto it = mmp.find(6); if(it!=mmp.end()) std::cout << it->first << ", " << it->second << std::endl; //prints: 6, 5 else std::cout << "Value does not exist!" << std::endl; it = mmp.find(66); if(it!=mmp.end()) std::cout << it->first << ", " << it->second << std::endl; else std::cout << "Value does not exist!" << std::endl; // This line would be executed.
エントリが
std::map
またはstd::multimap
存在するかどうかを調べるもう1つの方法は、count()
関数を使用して、指定されたキーに関連付けられている値の数を数えます。std::map
は各キーに1つの値しか関連付けていないため、count()
関数は0(キーがない場合)または1(存在する場合)を返すことができます。std::multimap
場合、同じキーに複数の値が関連付けられている可能性があるため、count()
は1より大きい値を返します。std::map< int , int > mp{ {1, 2}, {3, 4}, {6, 5}, {8, 9}, {3, 4}, {6, 7} }; if(mp.count(3) > 0) // 3 exists as a key in map std::cout << "The key exists!" << std::endl; // This line would be executed. else std::cout << "The key does not exist!" << std::endl;
ある要素が存在するかどうかだけが気になる場合、
find
は厳密には良いです。それはあなたの意図を記録し、multimaps
場合、最初に一致する要素が見つかると停止します。std::multimap
場合、同じキーを持つ複数の要素が存在する可能性があります。この範囲を取得するには、iteratorの下限(上限)と上限(上限)を持つstd::pair
を返すequal_range()
関数を使用します。キーが存在しない場合、両方のイテレータはend()
指します。auto eqr = mmp.equal_range(6); auto st = eqr.first, en = eqr.second; for(auto it = st; it != en; ++it){ std::cout << it->first << ", " << it->second << std::endl; } // prints: 6, 5 // 6, 7
要素数の確認
コンテナstd::map
は、マップが空であるかどうかに応じてtrue
またはfalse
を返すメンバー関数empty()
があります。メンバー関数size()
は、 std::map
コンテナに格納されている要素の数を返します。
std::map<std::string , int> rank {{"facebook.com", 1} ,{"google.com", 2}, {"youtube.com", 3}};
if(!rank.empty()){
std::cout << "Number of elements in the rank map: " << rank.size() << std::endl;
}
else{
std::cout << "The rank map is empty" << std::endl;
}
マップの種類
レギュラーマップ
マップは、キーと値のペアを含む連想型コンテナです。
#include <string>
#include <map>
std::map<std::string, size_t> fruits_count;
上記の例では、 std::string
はキータイプであり、 size_t
は値です。
キーはマップ内のインデックスとして機能します。各キーは一意でなければならず、注文する必要があります。
同じキーを持つ複数の要素が必要な場合は、
multimap
使用を検討してください(後述)値のタイプで順序が指定されていない場合、またはデフォルトの順序をオーバーライドする場合は、次のいずれかを指定します。
#include <string> #include <map> #include <cstring> struct StrLess { bool operator()(const std::string& a, const std::string& b) { return strncmp(a.c_str(), b.c_str(), 8)<0; //compare only up to 8 first characters } } std::map<std::string, size_t, StrLess> fruits_count2;
StrLess
比較器が2つのキーに対してfalse
を返す場合、実際の内容が異なっていても同じものとみなされます。
マルチマップ
マルチマップでは、同じキーを持つ複数のキーと値のペアをマップに格納できます。それ以外の場合は、そのインターフェイスと作成は通常のマップに非常に似ています。
#include <string>
#include <map>
std::multimap<std::string, size_t> fruits_count;
std::multimap<std::string, size_t, StrLess> fruits_count2;
ハッシュマップ(順序付けられていないマップ)
ハッシュマップには、通常マップと同様のキーと値のペアが格納されます。しかし、キーに関して要素を順序付けることはありません。代わりに、キーのハッシュ値を使用して、必要なキーと値のペアにすばやくアクセスします。
#include <string>
#include <unordered_map>
std::unordered_map<std::string, size_t> fruits_count;
順序付けられていないマップは通常は高速ですが、要素は予測可能な順序で格納されません。たとえば、 unordered_map
すべての要素を反復処理すると、一見無作為な順序で要素がunordered_map
ます。
ユーザー定義型をキーとしてstd :: mapを作成する
クラス内のキーをマップ内のキーとして使用できるようにするには、キーに必要なのは、それがcopiable
でassignable
です。マップ内の順序は、テンプレートの3番目の引数(およびコンストラクタが使用されている場合はその引数)によって定義されます。これはデフォルトではstd::less<KeyType>
に設定されています。デフォルトは<
演算子ですが、デフォルトを使用する必要はありません。比較演算子を書くだけです(できれば関数オブジェクトとして):
struct CmpMyType
{
bool operator()( MyType const& lhs, MyType const& rhs ) const
{
// ...
}
};
C ++では、 "compare"述部は厳密な弱い順序でなければなりません。特に、 compare(X,X)
は任意のX
に対してfalse
を返す必要があります。つまり、 CmpMyType()(a, b)
がtrueを返す場合、 CmpMyType()(b, a)
はfalseを返さなければならず、両方がfalseを返す場合、要素は等しいと見なされます。
厳格な弱い注文
これは、2つのオブジェクト間の関係を定義する数学的な用語です。
定義は次のとおりです。
f(x、y)とf(y、x)の両方がfalseの場合、2つのオブジェクトxとyは等価です。オブジェクトは、それ自体に相当する(非再帰不変不変によって)常に存在することに注意してください。
C ++の場合、指定された型のオブジェクトが2つある場合は、<と比較して次の値を返す必要があります。
X a;
X b;
Condition: Test: Result
a is equivalent to b: a < b false
a is equivalent to b b < a false
a is less than b a < b true
a is less than b b < a false
b is less than a a < b false
b is less than a b < a true
等価/以下を定義する方法は、オブジェクトのタイプに完全に依存します。