概况
Map和Multimap是将key/value pair 当做元素,进行管理。可以根据key的排序准则自动将元素排序。multimap允许重复元素,map不允许有重复,如图1所示。
图1 Maps和Multimaps
使用map和multimap之前需要包含头文件<map>:#include <map>;
map和multimap在std命名空间中被定义为class template:
namespace std
{
template <class Key, class T,
class Compare = less<Key>,
class allocator = allocator< pair<const Key, T> >
class map;
template <class Key, class T,
class Compare = less<Key>,
class allocator = allocator< pair<const Key, T> >
class multimap;
}
从以上代码可以看到,在map和multimap中所有元素的Key都被当做常数,是不能被修改的。因此,元素的实际类型是pair<const key, t>。
内部结构
和set关联式容器一样,map/multimap通常也通过平衡二叉树进行元素的内存管理,但是map/multimap是通过key进行自动排序,如图2所示。我们根据已知的key来搜寻某个元素时,搜索具有很好的性能,而根据value进行搜寻,性能不佳。由于map/multimap有“自动排序”功能,因此我们不能直接改变元素的key,因为修改了key将会破坏内部的正确顺序,如果需要修改key值,value值不变,则必须先把拥有该key的元素删除,然后再插入新的Key/value pair元素。
map/multimap排序定义准则方式同set定义方式。
map视为关联式数组
map/multimap拥有和set基本一样的操作函数,都不支持元素的直接存取,元素的存取均是通过迭代器进行,不过map有个例外:map提供下标操作符[],可直接存元素。并且下标操作符的索引值可以不为整型元素,可以是任意型别。这种接口称为关联式数组。
图3 下标操作符
和一般数组之间的差别不仅仅在于索引类型,还在于我们不可能存在数组越界情况,即使用错误的索引。如果使用一个可以作为索引,而该key尚不存在map中,map会重载operator[]插入新元素,新元素的value值有构造函数确定,一般为0.
例如
coll["hello"] = 21;
该语句会执行以下几个操作步骤:
1.处理coll["hello"];
如果存在键值”hello“的元素,以上则返回该元素的引用。
如果该键值”hello“不存在map中,则自动创建键值为”hello“的元素,key所对应的vaule是由默认构造函数进行赋值。
2.将21赋值给value
紧接着,”21“就通过赋值操作符赋值给新诞生的元素。
通过下标操作符接口,map的插入更加便捷,但该方式在效率上,同其他安插方式来的慢一些。
map安插新元素的四种方式
1.运用value_type
为了避免隐式转换,可以利用容器本身提供的value_type类型传递正确的型别,例如:
typedef map<string, int> StrIntMap;
StrIntMap Maps;
//方式一
Maps.insert(StrIntMap::value_type("hello", 21));
2.运用pair
//方式二
Maps.insert(pair<string, int>("Test", 22)); //发生隐身转换
Maps.insert(pair<const string, int>("Hua", 23));//没有隐身转换
3.运用make_pair()
//方式三
Maps.insert(make_pair("Wei", 24));
4.运用下标操作符
//方式四
Maps["Jin"] = 27;//仅支持map multimap不支持
Map/multimap运用实例
例子1
/****************************************************
*函数名称:AssociativeArrayExample
*功 能:将map当做关联数组使用
*作 者:Jin
*日 期:2016年5月24日
****************************************************/
void AssociativeArray()
{
std::cout << "********" << __FUNCTION__ << "********"<<std::endl;
typedef map<string, float> StringFloatMap;
StringFloatMap MapStocks;
//Insert some elements
MapStocks["BASF"] = 369.50;
MapStocks["VW"] = 413.50;
MapStocks["Daimler"] = 819.00;
MapStocks["BMW"] = 834.00;
MapStocks["Siemens"] = 842.00;
//print all elements
StringFloatMap::iterator pos;
for (pos = MapStocks.begin(); pos != MapStocks.end(); ++pos)
{
cout << "stock:" << pos->first << "\t\t";
cout << "price:" << pos->second << endl;
}
cout << endl;
//rename key from "VW" to "Volkswagen"
MapStocks["Volkswagen"] = MapStocks["VW"];//a[0] = a[2];
if (MapStocks.erase("VW") >= 1)
{
cout << "rename stocks success!" <<endl;
}
//print all elements
for (pos = MapStocks.begin(); pos != MapStocks.end(); ++pos)
{
cout << "stock:" << pos->first << "\t\t";
cout << "price:" << pos->second << endl;
}
cout << endl;
}
例子2
/****************************************************
*函数名称:MultiMapAsDict
*功 能:将multimap当做字典使用
*作 者:Jin
*日 期:2016年5月24日
****************************************************/
void MultiMapAsDict()
{
cout << "********" << __FUNCTION__ << "********"<<endl;
typedef multimap<string, string> StrStrMultiMap;
StrStrMultiMap MultimapDict;
//insert some elements in random order
MultimapDict.insert(make_pair("day", "tag"));
MultimapDict.insert(make_pair("strange", "fremd"));
MultimapDict.insert(make_pair("car","Auto"));
MultimapDict.insert(make_pair("smart","elegant"));
MultimapDict.insert(make_pair("trait","Merkmal"));
MultimapDict.insert(make_pair("strange","seltsam"));
MultimapDict.insert(make_pair("smart","klug"));
MultimapDict.insert(make_pair("smart","raffiniert"));
MultimapDict.insert(make_pair("clever","raffiniert"));
cout.setf(ios::left, ios::adjustfield);
cout << ' ' << setw(10) << "english "
<< "german " <<endl;
cout << setfill('-') << setw(20) <<""
<< setfill(' ') << endl;
//print all element
StrStrMultiMap::iterator pos;
for (pos = MultimapDict.begin(); pos != MultimapDict.end(); ++pos)
{
cout << ' ' << setw(10) << pos->first.c_str()
<< pos->second << endl;
}
cout << endl;
//print all vaules for key "smart"
string strKey("smart");
cout << strKey << ":" << endl;
for (pos = MultimapDict.lower_bound(strKey); pos != MultimapDict.upper_bound(strKey);++pos)
{
cout << "\t" << pos->second << endl;
}
cout << endl;
//print all keys for value is "raffiniert"
string strValue("raffiniert");
cout << strValue << ":" <<endl;
for (pos = MultimapDict.begin(); pos != MultimapDict.end();++pos)
{
if (pos->second == strValue)
{
cout << " " << pos->first << endl;
}
}
}
例子3
template <class K, class V>
class CValueEqual
{
private:
V value;
public:
CValueEqual(const V &v):value(v)
{
cout << "constructor is initial" <<endl;
}
bool operator()(pair<const K, V> elem)
{
return elem.second == value;
}
};
bool EqualValue(pair<const float, float> elem)
{
if (elem.second == 3)
{
return true;
}
else
{
return false;
}
}
/****************************************************
*函数名称:FindSpecialValue
*功 能:查找具有指定值的元素
*作 者:Jin
*日 期:2016年5月24日
****************************************************/
void FindSpecialValue()
{
typedef map<float, float> FloatFloatMap;
FloatFloatMap fMap;
FloatFloatMap::iterator pos;
//fill map
fMap[1] = 7;
fMap[2] = 4;
fMap[3] = 2;
fMap[4] = 3;
fMap[5] = 6;
fMap[6] = 1;
fMap[7] = 3;
//find element with key 3.0
pos = fMap.find(3.0);
if (pos != fMap.end())
{
cout << pos->first << ":"
<< pos->second << endl;
}
else
{
cout << "do not find element with key 3" << endl;
}
//find element with value 3.0
pos = find_if(fMap.begin(), fMap.end(), CValueEqual<float, float>(3.0));//方式一
//pos = find_if(fMap.begin(), fMap.end(), EqualValue);方式二
if (pos != fMap.end())
{
cout << pos->first << ":"
<< pos->second << endl;
}
else
{
cout << "do not find element with value 3" << endl;
}
}