1. STL 映射类简介
map
和 multimap
是键-值对容器,支持根据键进行查找,区别在于,后者能够存储重复的键,而前者只能存储唯一的键。
为了实现快速查找, STL map
和 multimap
的内部结构看起来像棵二叉树。这意味着在 map
或multimap
中插入元素时将进行排序;还意味着不像 vector
那样可以使用其他元素替换给定位置的元素,位于 map
中特定位置的元素不能替换为值不同的新元素,这是因为 map
将把新元素同二叉树中的其他元素进行比较,进而将它放在其他位置。
要使用 STL map
或 multimap
类,需要包含头文件 <map>
:
#include <map>
2. STL map 和 multimap 的基本操作
STL map
和 multimap
都是模板类,要使用其成员函数,必须先实例化。
2.1 实例化 std::map 和 std::multimap
要实例化将整数用作键、将字符串用作值的 map
或 multimap
,必须具体化模板类 std::map
或std::multimap
。
实例化模板类 map
时,需要指定键和值的类型以及可选的谓词(它帮助 map
类对插入的元素进行排序)。因此,典型的 map
实例化语法如下:
#include <map>
using namespace std;
...
map <keyType, valueType, Predicate=std::less <keyType>> mapObj;
multimap <keyType, valueType, Predicate=std::less <keyType>> mmapObj;
第三个模板参数是可选的。如果您值指定了键和值的类型,而省略了第三个模板参数, std::map
和 std::multimap
将把 std::less<>
用作排序标准,这将元素按升序排列。因此,将整数映射到字符串的 map
或 multimap
类似于下面这样:
std::map<int, string> mapIntToStr;
std::multimap<int, string> mmapIntToStr;
实例化示例:
int main ()
{
using namespace std;
// map and multimap key of type int to value of type string
map<int, string> a;
multimap<int, string> ma;
// map and multimap constructed as a copy of another
map<int, string> b(a);
multimap<int, string> mb(ma);
// map and multimap constructed given a part of another map or multimap
map<int, string> c(a.cbegin(), a.cend());
multimap<int, string> mc(ma.cbegin(),ma.cend());
return 0;
}
2.2 在 STL map 或 multimap 中插入元素
map
和 multimap
的大多数函数的用法类似,它们接受类似的参数,返回类型也类似。例如,要在这两种容器中插入元素,都可使用成员函数 insert
:
using namespace std;
map<int, string> d;
// insert pair of key and value using make_pair function
d.insert (make_pair (-1, "Minus One"));
鉴于这两种容器包含的元素都是键-值对,因此也可直接使用 std::pair
来指定要插入的键和值:
d.insert (pair <int, string>(1000, "One Thousand"));
另外,还可使用类似于数组的语法进行插入。是由下标运算符 []
支持的:
d[1000000] = "One Million";
还可使用 map
来实例化 multimap
:
multimap<int, std::string> md(d.cbegin(), d.cend());
插入代码示例:
#include <map>
#include <iostream>
#include <string>
using namespace std;
// 使用 typedef 指定别名,方便阅读
typedef map<int, string> MAP_INT_STRING;
typedef multimap<int, string> MMAP_INT_STRING;
// 使用迭代器来访问表示键的 first 以及表示值的second
template <typename T>
void DisplayContents (const T& cont)
{
for (auto element = cont.cbegin(); element != cont.cend(); ++ element)
{
cout << element->first << " -> " << element->second << endl;
}
cout << endl;
}
int main ()
{
MAP_INT_STRING mapIntToStr;
// 使用 value_type 插入键值对
mapIntToStr.insert(MAP_INT_STRING::value_type (3, "Three"));
// 使用 make_pair 函数插入键值对
mapIntToStr.insert(make_pair (-1, "Minus One"));
// 直接使用 pair 对象插入函数
mapIntToStr.insert(pair<int, string>(1000, "One Thousand"));
// 使用数组方式插入键值对
mapIntToStr[1000000] = "One Million";
cout << "The map contains " << mapIntToStr.size ();
cout << " key-value pairs. They are: " << endl;
DisplayContents(mapIntToStr);
// instantiate a multimap that is a copy of a map
MMAP_INT_STRING mmapIntToStr(mapIntToStr.cbegin(), mapIntToStr.cend());
// The insert function works the same way for multimap too
// A multimap can store duplicates - insert a duplicate
mmapIntToStr.insert (make_pair (1000, "Thousand"));
cout << endl << "The multimap contains " << mmapIntToStr.size();
cout << " key-value pairs. They are: " << endl;
cout << "The elements in the multimap are: " << endl;
DisplayContents(mmapIntToStr);
// The multimap can return number of pairs with same key
cout << "The number of pairs in the multimap with 1000 as their key: "
<< mmapIntToStr.count (1000) << endl;
return 0;
}
2.3 在 STL map 中查找元素
诸如 map
和 multimap
等关联容器都提供了成员函数 find()
,它让您能够根据给定的键查找值。 find()
总是返回一个迭代器:
multimap <int, string>::const_iterator pairFound = mapIntToStr.find(key);
如果使用的编译器遵循 C++11
标准,可使用关键字 auto
来简化迭代器声明:
auto pairFound = mapIntToStr.find(key);
编译器将根据 map::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;
完整示例代码如下:
#include <map>
#include <iostream>
#include <string>
using namespace std;
// 使用迭代器来访问表示键的 first 以及表示值的second
template <typename T>
void DisplayContents (const T& cont)
{
for (auto element = cont.cbegin(); element != cont.cend(); ++ element)
{
cout << element->first << " -> " << element->second << endl;
}
cout << endl;
}
int main ()
{
map<string, string> d;
d["a"] = "1";
d.insert(make_pair("b", "2"));
d.insert(make_pair("c", "3"));
DisplayContents(d);
string key = "c";
auto pairFound = d.find(key);
if (pairFound != d.end())
{
cout << "Key " << pairFound->first << " points to Value: ";
cout << pairFound->second << endl;
}
else
cout << "Sorry, pair with key " << key << " not in map" << endl;
return 0;
}
2.4 在 STL multimap 中查找元素
如果 2.3 小节程序使用的是 multimap
,容器可能包含多个键相同的键-值对,因此需要找到与指定键对应的所有值。为此,可使用 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; ++ counter )
{
cout << "Key: " << pairFound->first; // key
cout << ", Value [" << counter << "] = ";
cout << pairFound->second << endl; // value
++ pairFound;
}
}
else
cout << "Element not found in the multimap";
2.5 删除 STL map 或 multimap 中的元素
map
和 multimap
提供了成员函数 erase()
,该函数删除容器中的元素。调用 erase
函数时将键作为参数,这将删除包含指定键的所有键-值对:
mapObject.erase(key);
函数 erase()
的另一种版本接受迭代器作为参数,并删除迭代器指向的元素:
mapObject.erase(element);
还可使用迭代器指定边界,从而将指定范围内的所有元素都从 map
或 multimap
中删除:
mapObject.erase(lowerBound, upperBound);
完整示例代码:
#include <map>
#include <string>
#include <iostream>
using namespace std;
template<typename T>
void DisplayContents(const T& cont)
{
for (auto element = cont.cbegin(); element != cont.cend(); ++ element)
cout<< element->first<< " -> "<< element->second<< endl;
cout<< endl;
}
int main()
{
multimap<int, string> mmapIntToStr;
// Insert key-value pairs into the multimap
mmapIntToStr.insert(make_pair(3, "Three"));
mmapIntToStr.insert(make_pair(45, "Forty Five"));
mmapIntToStr.insert(make_pair(-1, "Minus One"));
mmapIntToStr.insert(make_pair(1000, "Thousand"));
// Insert duplicates into the multimap
mmapIntToStr.insert(make_pair(-1, "Minus One"));
mmapIntToStr.insert(make_pair(1000, "Thousand"));
cout<< "The multimap contains "<< mmapIntToStr.size();
cout<< " key-value pairs. "<< "They are: "<< endl;
DisplayContents(mmapIntToStr);
// Erasing an element with key as -1 from the multimap
auto numPairsErased = mmapIntToStr.erase(-1);
cout<< "Erased " << numPairsErased << " pairs with -1 as key."<< endl;
// Erase an element given an iterator from the multimap
auto pair = mmapIntToStr.find(45);
if(pair != mmapIntToStr.end())
{
mmapIntToStr.erase(pair);
cout<< "Erased a pair with 45 as key using an iterator"<< endl;
}
// Erase a range from the multimap...
cout << "Erasing the range of pairs with 1000 as key." << endl;
mmapIntToStr.erase(mmapIntToStr.lower_bound(1000), mmapIntToStr.upper_bound(1000) );
cout<< "The multimap now contains "<< mmapIntToStr.size();
cout<< " key-value pair(s)."<< "They are: "<< endl;
DisplayContents(mmapIntToStr);
}