概况
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定义方式。
图2 map/multimap 内部数据结构
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 << " "; 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 << " "; 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 << " " << 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; } }