关联容器
关联容器: 通过键(key)储存与读取元素
顺序容器: 通过元素在容器中的位置顺序储存,访问
关联容器类型
map 关联数组:元素通过键来存储和读取
set 大小可变的集合,支持通过键实现的快速读取, 具有集合的性质
multimap 支持同一个键多次出现的 map 类型
multiset 支持同一个键多次出现的 set 类型
与关联容器相关的pair
pair:一种类模板, 定义在头文件utility中
T1,T2为元素类型, 可以是容器或者类,pair类型
pair< T1,T2 >p , p对象当前具有两个属性T1,T2
访问pair对象直接使用p.first , p.second 访问其数据成员
pair<int, pair<string,int> >p1(1,"hello",1);
//注意p1前面两个大于号之间要留有空格,防止编译时看成位运算
//p1具有三个属性(int string int)
cout<<p1.first<<p1.second.first<<p1.second.second;
//first,second分别对应着p1对象的两个数据成员
关联容器
关联容器具有顺序容器大部分操作 ,但没有front, push_front, pop_front, back, push_back, pop_back,assign, resize操作
具有以下构造函数:
- C< T >c;
- C< T >c1(c2);
- C< T >c(b,e)
关联容器不能通过容器大小来定义(即C< T >c(n) ), 当关联容器通过大小来定义, 就无法确定初始化的那个对象需要采用哪个值或哪些值来初始化,若采用0来初始化这n个对象时将造成多个键重复,这样就无法知道键所对应的值是哪个
map类型
map: 关联数组(采用key获取值与数组采用下标获取值一致)
map构造函数
- map< k,v >m; 创建空的map对象, 其键与值为k, v
- map< k,v >m(m2); 创建m2的副本, m2与m必须具有相同的key,value
- map< k,v >m(b,e); m储存迭代器b,e之间元素的副本, 元素必须能转换为pair< const k, v >
map迭代器进行解引用的时候将产生pair对象
//m为存在键值的元素
map<string,int>::iterator iter=m.begin();
cout<<iter->first<<iter->second;
键类型约束问题
map中key不但具有类型, 还具有一个相关的比较函数,比较函数必须在键类型上定义严格弱排序,因此在map元素插入的过程中元素会依据键的大小关系进行排序,键值类型必须定义”<”操作符
详情观看转载
https://blog.csdn.net/qq_29344757/article/details/7869
例:
map对象可以使用vector< int >::iterator为key, iterator对象内置弱排序(iter可进行大小,加减比较操作)
map对象不可以使用list< int >::iterator为key, iterator对象内不能进行弱排序(iter只具有”==”与”!=”操作)
采用下标访问map对象
int main(){
map<string,int>m;
m["hello"]=1;
m["world"]=2;
map<string,int>::iterator iter=m.begin();
while(iter!=m.end())
{
cout<<iter->first;
iter++;
}
cout<<m["!!!"];
return 0;
}
针对m的过程
- 在m中查找hello的元素,但未找到
- 将hello作为key插入m中,类型为const string, 在例子中初始值为0
- 将键值对插入到m中
- 读取插入的元素, 对其赋值为1
- 同理,m[“world”]与m[“hello”]的过程类似
- 最后的m[“!!!”]表示: 访问下标(key)未在m中的键值对,那么将会在m中添加当前键, 其值初始化为0(使用默认的构造函数进行初始化)
注:map采用下标的访问过程与vector截然不同, map中如上第6步操作, 而vector将会抛出异常
map中insert的使用
map中的insert用法与顺序容器一致, 不同在于插入的元素必须是pair类型的
map提供的insert
- m.insert(e): e是与m类型一致的pair类型, 如果e.first不存在m中, 那么将插入e.first作为键, 其值为e.second, 返回void; 若e存在m中则返回一个pair类型对象(假设对象名是p), p.first的值是map型迭代器(迭代器指向的位置是e.first), p.second的值是一个bool类型对象(值为false), 表示是否插入该元素
- m.insert(b,e): 插入迭代器b,e范围之间的元素(元素类型必须为m.value_type类型的键值对), 不能指明总共插入多少个元素
- m.insert(iter,e): 以iter为起点位置,自动查找可适合的新元素储存位置, 返回一个迭代器指向当前插入的元素的位置
注:插入的元素对象既可以是pair,也可以是map< T1,T2 >::value_type(key,value); 谨记value_type是pair< const key, value >的同义词
例: 用于解释m.inset(e)的返回值操作
//统计文章中单词出现的个数
map<string,int>m;
pair<string,int>p_tran//将每次输入的world转化为pair类型
string world
while(cin>>world){
pair<map<string,int>::iterator,bool>p_sum=m.insert( p_tran(world,1) );
if(!p_sum->second)
++(p_sum->first->second); //表示对m中元素的值进行自增,不加括号时,注意符号优先级
}
map<string,int>::iterator iter=m.bengin();
while(iter!=m.end()){
cout<<iter->first<<" 单词数目: "<<iter->second;
++iter;
}
p_sum的设计方式请参考m.insert(e)的返回值确定;
map中元素查找
- 直接类似数组的下标方式进行查找, 但是若元素未在容器中将出现插入操作,且关联值为0, 给程序造成一定的负担
- m.count(key): 返回m中key出现的次数
- m.find(key): key存在m中,返回指向key的迭代器, 不存在时返回超出末端的迭代器(所谓end())
map中元素的删除
- m.erase(key): 在m中删除键为key的元素,返回size_type类型的值(表示删除的元素的个数)
- m.erase(iter): 删除iter所指向的元素, iter!=end()且iter存在, 返回void
- m.erase(b,e): 删除迭代器b,e范围(b,e必须为有效范围,指向m中的元素或最后一个元素的后一个位置)内的元素, 返回void
当进行map对象的遍历的时候,采用const_iterator型迭代器