マップ、マルチマップ
map と multimap はキーと値のペアのコンテナーであり、キーに従って検索されます。
同様に、内部構造はバイナリ ツリーに似ているため、要素を挿入するときにソートする必要があり、ベクトルのように特定の位置の要素を他の要素に置き換えることはできません。
ヘッダー ファイル: #include <マップ>
インスタンス化する
/*
实例化语法:
map <keyType, valueType, Predicate=std::less <keyType>> mapObj;
multimap <keyType, valueType, Predicate=std::less <keyType>> mmapObj;
第三个模板参数可选:默认是std::less<>用作排序标准
*/
#include <map>
#include <iostream>
#include <string>
using namespace std;
template <typename T>
struct reverseSort
{
bool operator()(const T& key1, const T& key2)
{
return key1 > key2;
}
};
int main()
{
// 初始化1:int -> string
map <int, string> mapIntToString1;
multimap <int, string> multimapIntToString1;
// 2. 以另一个 map/multimap 进行初始化
map <int, string> mapIntToString2(mapIntToString1);
multimap <int, string> multimapIntToString2(multimapIntToString2);
// 3. 以另一个 map/multimap 的一部分进行初始化
map <int, string> mapIntToString3(mapIntToString1.cbegin(),
mapIntToString1.cend());
multimap <int, string> multimapIntToString3(multimapIntToString1.cbegin(),
multimapIntToString1.cend());
// 4. 带谓词的初始化
map <int, string, reverseSort<int>> mapIntToString4
(mapIntToString1.cbegin(), mapIntToString1.cend());
// 用map实例化multimap
multimap <int, string, reverseSort<int>> multimapIntToString4
(mapIntToString1.cbegin(), mapIntToString1.cend());
system("pause");
return 0;
}
入れる
/*
用成员函数 insert:
1. make_pair(key, value)
2. std::pair(key, value)
3. 类似数组的语法:mapIntToStr [1000000] = "One Million";
*/
#include <iostream>
#include <string>
#include <map>
using namespace std;
typedef map <int, string> MAP_INT_STRING;
typedef multimap <int, string> MMAP_INT_STRING;
template <typename T>
void DisplayElement (const T& input)
{
for (auto iElement = input.cbegin(); iElement != input.cend(); ++iElement)
{
cout << iElement->first << " -> " << iElement->second << endl;
}
cout << endl;
}
int main()
{
MAP_INT_STRING mapIntToString;
// value_type:stl容器盛装的数据的数据类型,这里就是<int, string>
mapIntToString.insert(MAP_INT_STRING::value_type(3, "Three"));
// make_pair (key, value)
mapIntToString.insert(make_pair(-1, "Minus one"));
// pair
mapIntToString.insert(pair <int, string> (1000, "One thousand"));
// 数组语法添加元素
mapIntToString[1000000] = "One million";
cout << "The map contains " << mapIntToString.size();
cout << " key-value pairs. They are: " << endl;
DisplayElement(mapIntToString);
// 以map实例化一个multimap
MMAP_INT_STRING mmapIntToString (mapIntToString.cbegin(),
mapIntToString.cend());
mmapIntToString.insert(make_pair(1000, "Thousand"));
cout << endl << "The multimap contains" << mmapIntToString.size();
cout << "The elements in the multimap are: " << endl;
DisplayElement(mmapIntToString);
cout << "The number of pairs in the mutimap with 1000 as their key: "
<< mmapIntToString.count(1000) << endl;
system("pause");
return 0;
}
見上げる
multimap::find() は常に次のようなiteratorを返します。
auto pairFound = mmapIntToStr.find(key); // C++11
mutimap <int, string>::const_iterator iPairFound = mapIntToString.find(key);
もう一度思い出してください:
イテレータを使用する前に、 find() を使用して見つかった値にアクセスする前に、 find() が成功を返すことを確認してください。
if (pairFound != mapIntToStr.end())
{
cout << "Key " << pairFound->first << " points to Value: ";
cout << pairFound->second << endl;
}
else
cout << "Sorry, pair with key " << key << " not in map" << endl;
メンバー multimap::find() の使用法について:
#include <map>
#include <string>
#include <iostream>
using namespace std;
template <typename T>
void DisplayContents (const T& input)
{
for (auto iElement = input.cbegin()
; iElement != input.cend()
; ++iElement)
{
cout << iElement->first << " points to "
<< iElement->second << endl;
}
cout << endl;
}
int main()
{
map <int, string> mapIntToString;
mapIntToString.insert(make_pair(3, "Three"));
mapIntToString.insert(make_pair(45, "Fifty five"));
mapIntToString.insert(make_pair(-1, "Minus one"));
mapIntToString.insert(make_pair(1000, "One Thousand"));
cout << "The map contains " << mapIntToString.size();
cout << " key-value pairs. They are:" << endl;
DisplayContents(mapIntToString);
cout << "Enter the key you wish to find: ";
int key = 0;
cin >> key;
auto iPairFound = mapIntToString.find(key);
if (iPairFound != mapIntToString.cend())
{
cout << "Key " << iPairFound->first << " points to Value: ";
cout << iPairFound->second << endl;
}
else
{
cout << "The pair with key " << key << " not in map" << endl;
}
system("pause");
return 0;
}
見上げる
multimap::count( ) は、指定されたキーに対応する値の数を決定し、これらの隣接する値にアクセスするために反復子をインクリメントします。
auto pairFound = mmapIntToStr.find(key);
// Check if find() succeeded
if(pairFound != mmapIntToStr.end())
{
// Find the number of pairs that have the same supplied key
size_t numPairsInMap = mmapIntToStr.count(1000);
for(size_t counter = 0;
counter < numPairsInMap; // stay within bounds
++ counter )
{
cout << "Key: " << pairFound->first; // key
cout << ", Value [" << counter << "] = ";
cout << pairFound->second << endl; // value
++ pairFound; // ******递增迭代*******
}
}
else
cout << "Element not found in the multimap";
消去
/*
1. 将键作为参数,这将删除包含指定键的所有键-值对:
mapObject.erase (key);
2. 接受迭代器作为参数,并删除迭代器指向的元素:
mapObject.erase(element);
3. 使用迭代器指定边界,从而将指定范围内的所有元素都从 map 或 multimap 中删除:
mapObject.erase (lowerBound, upperBound);
*/
#include <iostream>
#include <map>
#include <string>
using namespace std;
template <typename T>
void DisplayContents (const T& input)
{
for (auto iElement = input.cbegin()
; iElement != input.cend()
; ++iElement)
{
cout << iElement->first << " points to "
<< iElement->second << endl;
}
cout << endl;
}
int main()
{
multimap <int, string> mmapIntToString;
mmapIntToString.insert(make_pair(3, "Three"));
mmapIntToString.insert(make_pair(45, "Forty five"));
mmapIntToString.insert(make_pair(-1, "Minus one"));
mmapIntToString.insert(make_pair(1000, "One thousand"));
mmapIntToString.insert(make_pair(-1, "Minus one(two)"));
mmapIntToString.insert(make_pair(1000, "One Thousand(two)"));
cout << "The multimap contains " << mmapIntToString.size();
cout << " key-value pairs. " << "They are: " << endl;
DisplayContents(mmapIntToString);
auto NumPairsErased = mmapIntToString.erase(-1);
cout << "Erased " << NumPairsErased << " pairs with -1 as key." << endl;
auto iPairLocator = mmapIntToString.find(45);
if(iPairLocator != mmapIntToString.cend())
{
mmapIntToString.erase(45);
cout << "Erased a pair with 45 as key using an iterator" << endl;
}
cout << "Erasing the range of pairs with 1000 as key." << endl;
mmapIntToString.erase(mmapIntToString.lower_bound(1000),
mmapIntToString.upper_bound(1000));
cout << "The multimap now contains " << mmapIntToString.size();
cout << " key-value pair(s)." << "They are:" << endl;
DisplayContents(mmapIntToString);
system("pause");
return 0;
}
lower_bound() と upper_bound() について?
カスタム述語の順序付け
別の並べ替え基準を提供するには、バイナリ述語 -->クラスまたは、operator()を実装する構造体を記述します。
template<typename keyType>
struct Predicate
{
bool operator()(const keyType& key1, const keyType& key2)
{
// your sort priority logic here
}
};
// 声明map
map <keyType, valueType, Predicate> mapObject;
キーが std::string 型であるマップの場合、デフォルトの順序付け述語 std::less により、std::string クラスで定義された < 演算子に従って順序付けが行われるため、大文字と小文字が区別されます。1 つの解決策は、次のように、大文字と小文字を区別しない比較に基づいて true または false を返すマップをインスタンス化するときに並べ替え述語を提供することです。
#include <iostream>
#include <algorithm>
#include <map>
#include <string>
using namespace std;
template <typename T>
void DisplayContents (const T& input)
{
for (auto iElement = input.cbegin()
; iElement != input.cend()
; ++iElement)
{
cout << iElement->first << " points to "
<< iElement->second << endl;
}
cout << endl;
}
struct IgnoreCase
//class IgnoreCase
{
//public:
bool operator()(const string& str1, const string& str2) const
{
string str1NoCase(str1), str2NoCase(str2);
transform(str1.begin(), str1.end(), str1NoCase.begin(), ::tolower);
transform(str2.begin(), str2.end(), str2NoCase.begin(), ::tolower);
return (str1NoCase < str2NoCase);
}
};
typedef map <string, string> DIRECTORY_WITHCASE;
typedef map <string, string, IgnoreCase> DIRECTORY_NOCASE;
int main()
{
DIRECTORY_NOCASE dirCaseInsensitive;
dirCaseInsensitive.insert(make_pair("John", "2345764"));
dirCaseInsensitive.insert(make_pair("JOHN", "2345764"));
dirCaseInsensitive.insert(make_pair("Sara", "42367236"));
dirCaseInsensitive.insert(make_pair("Jack", "32435348"));
cout << "Displaying contents of the case-insensitive map: " << endl;
DisplayContents(dirCaseInsensitive);
DIRECTORY_WITHCASE dirCaseSensitive(dirCaseInsensitive.begin(),
dirCaseInsensitive.end());
cout << "Displaying contents of the case-sensitive map: " << endl;
DisplayContents(dirCaseSensitive);
cout << "Please enter a name to search: " << endl << "> ";
string strNameInput;
cin >> strNameInput;
auto iPairInNoCaseDir = dirCaseInsensitive.find(strNameInput);
if (iPairInNoCaseDir != dirCaseInsensitive.cend())
{
cout << iPairInNoCaseDir->first << "'s number in the case-insensitive";
cout << " directory is: " << iPairInNoCaseDir->second << endl;
}
else
{
cout << strNameInput << "'s number not found ";
cout << "in the case-insensitive directory" << endl;
}
auto iPairInCaseSensDir = dirCaseSensitive.find(strNameInput);
if (iPairInCaseSensDir != dirCaseSensitive.cend())
{
cout << iPairInCaseSensDir->first << "'s number in the case-sensitive";
cout << " directory is: " << iPairInCaseSensDir->second << endl;
}
else
{
cout << strNameInput << "'s number was not found ";
cout << "in the case-sensitive directory" << endl;
}
system("pause");
return 0;
}
構造体 PredIgnoreCase をクラスとして宣言することもできます。その場合、キーワード public をoperator() に追加する必要があります。
std::map は、vector や list に比べて検索性能は高いですが、要素が増えると検索速度が低下し、所要時間はマップに含まれる要素の対数に比例します。
unowned_map、unordered_multimap
このクラスはハッシュ テーブルに基づいています。
要素の検索にかかる時間と同様に、挿入と削除の平均時間は固定されています。
ヘッダー ファイル: #include <unowned_map>
find() が呼び出されると、要素はキーに従って検索され、キーに従ってインデックスを計算するには次の関数を呼び出す必要があります。
Index = HashFunction(key, TableSize);
初期化、検索、挿入などの操作はマップと同様です。unowned_map には、ソート順序の計算に使用されるハッシュ関数が含まれていることに注意してください。
unordered_map<int, string>::hasher hFn = umapIntToStr.hash_function();
size_t hashingVal = hFn(1000);
// 在元素数达到或接近桶数时,它将自动执行负载均衡:
// load_factor( ) 指出了 unordered_map 桶的填满程度
cout << "Load factor: " << umapIntToStr.load_factor() << endl;
// load_factor( ) 超过max_load_factor( )时,unordered_map 将重新组织以增加桶数,并重建散列表
cout << "Max load factor = " << umapIntToStr.max_load_factor() << endl;
// 桶数量
cout << "Max bucket count = " << umapIntToStr.bucket_count() << endl;
具体的な例:
#include <unordered_map>
#include <string>
#include <iostream>
using namespace std;
template <typename T1, typename T2>
void DisplayUnorderedMap (unordered_map<T1, T2>& Input)
{
cout << "Number of pairs, size(): " << Input.size() << endl;
cout << "Bucket count: " << Input.bucket_count() << endl;
cout << "Load factor: " << Input.load_factor() << endl;
cout << "Max load factor: " << Input.max_load_factor() << endl;
for (auto iElement = Input.cbegin(); iElement != Input.cend(); ++iElement)
{
cout << iElement->first << " -> " << iElement->second << endl;
}
cout << endl;
}
int main()
{
unordered_map <int, string> umapIntToStr;
umapIntToStr.insert(make_pair(1, "One"));
umapIntToStr.insert(make_pair(45, "Forty five"));
umapIntToStr.insert(make_pair(1001, "Thousand one"));
umapIntToStr.insert(make_pair(-2, "Minus Two"));
umapIntToStr.insert(make_pair(-1000, "Minus One Thousand"));
umapIntToStr.insert(make_pair(100, "One Hundred"));
umapIntToStr.insert(make_pair(12, "Twelve"));
umapIntToStr.insert(make_pair(-100, "Minus One Hundred"));
DisplayUnorderedMap<int, string>(umapIntToStr);
cout << endl;
/*
Number of pairs, size(): 8
Bucket count: 17
Load factor: 0.470588
Max load factor: 1
-100 -> Minus One Hundred
12 -> Twelve
45 -> Forty five
-1000 -> Minus One Thousand
1 -> One
-2 -> Minus Two
1001 -> Thousand one
100 -> One Hundred
*/
cout << "Inserting one more element:" << endl;
umapIntToStr.insert(make_pair(300, "Three handred"));
DisplayUnorderedMap<int, string>(umapIntToStr);
cout << endl;
/*
Inserting one more element:
Number of pairs, size(): 9
Bucket count: 17
Load factor: 0.529412
Max load factor: 1
-100 -> Minus One Hundred
12 -> Twelve
300 -> Three handred
45 -> Forty five
-1000 -> Minus One Thousand
1 -> One
-2 -> Minus Two
1001 -> Thousand one
100 -> One Hundred
*/
cout << "Enter key to find for: ";
int key = 0;
cin >> key; // 300
auto iElementFound = umapIntToStr.find(key);
if (iElementFound != umapIntToStr.end())
{
cout << "Found key " << iElementFound->first << " points to value: ";
cout << iElementFound->second << endl;
}
else
{
cout << "Key has no corresponding value in unordered map!" << endl;
}
// Enter key to find for: Found key 300 points to value: Three handred
system("pause");
return 0;
}