map是STL的一个容器,和set一样,map也是一种关联式容器。它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值)的数据处理能力,由于这个特性,有助于我们处理一对一数据。这里说下map内部数据的组织,map内部是自建一颗红黑树(一种非严格意义上的平衡二叉树),这颗树具有对数据自动排序的功能,所以在map内部所有的数据都是有序的。
使用map需注意以下几点:
1、 查找、插入、删除时间复杂度为log n
2、 插入元素不会使任何迭代器失效,删除只会使指向被删除元素的迭代器失效。
3、 Map中的key值是唯一的不可更改的。
Map部分成员函数:
1、 无参构造函数以及自定义比较子
原型:
map( );
explicit map(
constTraits& _Comp
);
map(
constTraits& _Comp,
const Allocator&_Al
);
map(
const map&_Right
);
#include <iostream> #include <map> #include <string>
using namespace std;
//传递引用或指针 报错 bool compare (string s1,string s2 ){ return s1.compare(s2)<0;} //传递引用或指针 报错 struct classcomp {bool operator()(string s1,string s2) const{return s1.compare(s2) < 0;}}; int main () { map<int,string> mapstr;//使用默认的key_comp map<string,string,classcomp> strclasscomp;//使用重载()操作符的类充当比较子 bool(*fn_pt)(string,string) = compare; map<string,string,bool(*)(string,string)> mapfuncp(fn_pt);//使用函数指针充当比较子
map<string,string,bool(*)(string,string)>::key_compare key_comp_copy = mapfuncp.key_comp();//使用map对象中的比较子
cout<<"test string compare"<<key_comp_copy("aaa","aab")<<endl;
mapstr[0] = "aaaaa"; mapstr[1] = "bbbbb"; strclasscomp["aclass"] = "aaaaa"; strclasscomp["bclass"] = "bbbbb"; mapfuncp["afunc"] = "aaaaafuncpointer"; mapfuncp["bfunc"] = "bbbbbfuncpointer"; cout<<" defalut constructor : element 0:"<<mapstr[0]<<endl; cout<<" class compare constructor : element \"bclass\":"<<strclasscomp["aclass"]<<endl; cout<<" functionpointer compare constructor : element \"afunc\":"<<mapfuncp["afunc"]<<endl;
int k; cin>>k; return 0; } |
2、 范围构造函数以及拷贝构造函数
原型:template<class InputIterator>
map (InputIterator first, InputIteratorlast,
const key_compare& comp = key_compare(),
const allocator_type& alloc = allocator_type());
代码:
map<int,int> mapint; mapint[0] = 0; mapint[2] = 2; map<int,int> mapint2(++mapint.begin(),mapint.end()); map<int,int> mapint3(mapint); cout<<" mapint2 size"<<mapint2.size()<<endl; cout<<" mapint3 size"<<mapint3.size()<<endl; |
3、 Insert
因为map中的主键是无重复的,所以如果插入的元素主键已经存在,新元素并不会被插入,返回已存在主键元素的迭代器。
原型:
pair<iterator,bool> insert (constvalue_type& val);
iterator insert (iterator position, constvalue_type& val);
template <class InputIterator>
voidinsert (InputIterator first, InputIterator last);
参数:
Val
被拷贝(或移动C++11)到新插入元素中的值。
成员类型value_type 是该容器的元素的类型,在 map 中被定义为 std::pair<const key_type,mapped_type>。
position
暗示新元素将要被插入的位置。
如果position 指向的元素将会在被插入元素之前,当前函数会对插入耗时进行优化。
需要注意的是这仅仅只是一个暗示,而不会强制新的元素插入到某个位置。
first, last
分别指向一个范围中初始及末尾位置的输入迭代器。这个范围即 [first,last) ,包括 first 到 last间的所有元素,包括first 指向的元素,但不包括 last指向的元素。
il
一个初始化列表对象。编译器将根据初始化列表声明体自动创建该对象。
成员类型value_type 是该容器的元素的类型,在 map 中被定义为 std::pair<const key_type,mapped_type>。
返回
单元素版(1) 返回一个二元组(Pair)。成员 pair::first 被设置为指向新插入元素的迭代器或指向等值的已经存在的元素的迭代器。成员 pair::second 是一个 bool 值,如果新的元素被插入,返回 true,如果等值元素已经存在(即无新元素插入),则返回 false。
使用暗示版(2) 返回一个指向被插入元素或者已经存在的元素的迭代器。
其它版本无返回。
代码:
typedef pair <int, int> Int_Pair; pair< map<int,int>::iterator, bool > pr; map<int,int> foo1; foo1.insert(std::pair<int,int>(1,10));//参数方式一 foo1.insert(Int_Pair(5,50));//参数方式二 foo1.insert(map<int,int>::value_type(7,70));//参数方式三 pr = foo1.insert(map<int,int>::value_type(8,80)); PrintIntIntMap(foo1,"插入四个二元组:"); cout<<"after insert <8,80> 返回值:"<<pr.first->first<<" "<<pr.first->second<<" "<<pr.second<<endl;//8 80 1 插入成功 pr = foo1.insert(map<int,int>::value_type(8,85)); cout<<"after insert <8,85> 返回值:"<<pr.first->first<<" "<<pr.first->second<<" "<<pr.second<<endl;//8 80 0 插入失败 map<int,int>::iterator it; // 作为演示,先定位键值 5 it = foo1.find(5); // 通过暗示插入键值 6 map<int,int>::iterator iter; iter = foo1.find(8);
foo1.insert(it,std::pair<int,int>(6,60)); PrintIntIntMap(foo1,"通过键值5暗示插入键值6:"); cout<<" 插入之后 验证指向8的iterator是否失效:"<<iter->second<<endl;//输出为80,,迭代器未失效
//暗示并未起作用,map自动排序 map<int,int>::iterator itt; // 作为演示,先定位键值 6 itt = foo1.find(6); // 通过暗示插入键值 3 foo1.insert(itt,std::pair<int,int>(3,30)); PrintIntIntMap(foo1,"通过键值6暗示插入键值3:");
std::map<int,int> foo2; it = foo1.begin(); std::advance(it,1); foo2.insert(it,foo1.end()); PrintIntIntMap(foo2,"范围插入获得foo2:"); |
|
如果插入单个元素且无暗示,时间复杂度为 O(logn),其中 n 为容器的大小。
如果插入单个元素且有最优位置(Position)暗示,时间复杂度为 O(1),这是一个平均分摊后的常值(Amortizedconstant)。
如果插入多个元素,时间复杂度为O(nlogn),“第一个” n 为插入元素数,“第二个” n 为插入元素数加容器大小。如果插入的范围中的元素已经按同样的排序规则排序,执行过程将被优化,时间复杂度甚至会降到 O(n)。
迭代器有效性:不会改变。
数据争用相关:容器被修改。并发的访问已经存在的元素是安全的。并发的迭代容器中的某个范围是不安全的。
4、 Erase删除单个元素,clear清空
原型:
void erase (iterator position);
size_type erase (const key_type& k);
void erase (iterator first, iterator last);
参数及返回值
position
指向将要从当前容器中移除的单个元素的迭代器。
iterator、const_iterator 都是成员类型,被定义为指向元素的双向迭代器类型。
k
将要从当前容器中移除的元素的键值。
成员类型key_type 是存储在当前容器中的元素的主键的类型,作为 map 实例化时第一个模板参数(Key)的别名而存在。
first,last
分别指向一个范围中初始及末尾位置的输入迭代器。这个范围即 [first,last) ,包括 first 到 last间的所有元素,包括first 指向的元素,但不包括 last指向的元素。
返回
对于版本(2),返回被删除元素的个数,对于 map 容器来说,最多是 1。
成员类型size_type 是一个无符号整数类型。
代码:
map<int, int> m; map<int, int>::iterator pIter, Iter1, Iter2; int i; map<int, int>::size_type n; typedef pair<int, int> Int_Pair;
for (i = 1; i < 5; i++) { m.insert(Int_Pair(i, i*i));
} Iter1 = m.find(4); Iter2 = m.find(2); cout << "before the 2nd element is deleted, the map m is:"; for (pIter = m.begin(); pIter != m.end(); pIter++) cout << " " << pIter->second; cout << "." << endl; cout<<"before delete 2nd element the iterator:Iter1="<<Iter1->first<<" Iter2="<<Iter2->first<<endl; // The 1st member function removes an element at a given position Iter1 = ++m.begin(); m.erase(Iter1);
cout << "After the 2nd element is deleted, the map m1 is:"; for (pIter = m.begin(); pIter != m.end(); pIter++) cout << " " << pIter->second; cout << "." << endl; // cout<<"after delete 2nd element the iterator:Iter1="<<Iter1->first<<" Iter2="<<Iter2->first<<endl;//迭代器失效,异常退出
Iter1 = ++m.begin(); Iter2 = --m.end(); m.erase(Iter1, Iter2); cout << "After delete element the range, the map m is:"; for (pIter = m.begin(); pIter != m.end(); pIter++) cout << " " << pIter->second; cout << "." << endl;
m.erase(1); cout << "After delete element by key = 1, the map m is:"; for (pIter = m.begin(); pIter != m.end(); pIter++) cout << " " << pIter->second; cout << "." << endl; |
时间复杂度
版本(1),时间复杂度为 O(1),这是一个平均分摊后的常值(Amortizedconstant)。
版本(2),时间复杂度为O(logn),其中 n 为容器大小。
版本(3),时间复杂度为O(logn),其中 n 为容器大小加上first 与 last之间的线性距离。
迭代器有效性
所有指向被删除元素的迭代器、指针及引用都将会失效。
其它的迭代器、指针及引用在调用该函数之后,仍然保持有效性。
数据争用相关
容器被修改。
被删除元素被修改。并发地访问其它元素是安全的。
并发的迭代容器中的某个范围是不安全的。
异常安全性相关
除非容器的比较对象抛出异常,不然当前函数绝不会抛出异常(No-throw guarantee,无异常抛出保证)。
否则,如果仅仅是删除单个元素,发生异常时,容器无任何改变(Strong guarantee,强异常安全性保证)。
否则,容器将处在一个有效的状态,但不保证数据是否发生改变(Basic guarantee,基本异常保证)。
如果传入无效的position 或范围,将导致无法预测的行为。
Clear:
复杂度
时间复杂度为 O(n)(元素析构消耗)。
迭代器有效性
与当前容器有关的迭代器、引用及指针都将失效。
数据争用
容器被修改。
容器中的所有元素被修改。
异常安全性
无异常抛出保证:从不抛出异常。
5、 Swap 交换两个map中的内容
void swap (map& x);
在调用该函数之后,当前容器中的内容是那些原来在 x 中的,而 x 中的内容则是之前在当前容器中的。所有指向两个容器中的元素的迭代器、指针及引用保持有效。
复杂度
时间复杂度为 O(1)。
迭代器有效性
所有指向两个容器中的元素的迭代器、指针及引用保持有效,且指向的元素跟调用该函数前的相同,只是已属于另个容器。
末尾(End)迭代器不指向元素,可能会失效。
数据争用相关
两个容器都被修改过。
无任何元素被访问过。
异常安全性相关
如果容器中的内存分配器相等(Compareequal),或者它们的分配器特征表明各自需要传播(C++11),当前函数从不抛出异常(No-throwguarantee,无异常抛出保证)。
否则,将导致不确定的行为。