顺序容器是按照元素在容器中位置来保存和访问的,而关联容器则不同,它是通过关键字来进行保存和访问。C++标准库提供了8个关联容器,根据有无重复关键字,有序还是无序保存来区分:
map和set是主要的两种关联容器,map中元素为键-值,关键字起到索引作用,值为相关联数据,set只包含一个关键字。
关联容器的额外的类型别名:
key_type: 容器的关键字类型
mapped_type: 每个关键字关联的类型,只适用map;
value_type: 对于set与key_type相同,对于map为pair<const key_type, mapped-type>
例:map<int ,string>::key_type v ;v为int类型
map<int ,string>::mapped_type v ;v为string类型
map<int ,string>::value_type v ;v为pair<const int,string>
pair类型
在上面的代码中已经看到了pair的应用了,pair为标准库类型,在文件utility,一个pair保存两个数据,类似容器,它的实现是一个结构体,当需要将两个不同类型的值保存在一个数据类型中时pair很实用。具体初始化:
pair<int, string> s(2,"abs"); //直接赋值;
pair<int, string> s1;
pair<int, string> s2;
s1 = make_pair(3,"abs"); //函数赋值
s2.first = 1;
s2.second = "aba"; //按内部成员赋值
一、map
map建立了键(key)和值(value)的对应关系,key 和 value可以是任意需要的类型, 需要#include <map>
。定义如:map<int, string> m;
。
1、插入数据
改变map中的条目非常简单,因为map类已经对[]操作符进行了重载
enumMap[1] = “One”;
enumMap[2] = “Two”;
…
注意map存储元素是按关键字进行排序的(从小到大),与数据添加的先后无关,还可以调用函数进行数据插入:
my_Map.insert(map<string, int>::value_type("b",2));
my_Map.insert(pair<string,int>("c",3));
2、查找数据
map中查找数据主要有两种方式,一种通过关键字来查找,一种利用find函数。
map<int, string> m;
string ss = m[2]; //2为关键字,只有map中存在关键字2时才会成功,否则会插入一个键值为2的元素,初值为空;
m[2] += "ss"; //2关键字存在时为赋值操作,不存在时为插入操作;
m.find(key),返回对应的迭代器
//注意当获取一个map迭代器itr之后,
//itr->first为对应元素的键值,itr->second为对应元素的值
3、删除数据
移除某个map中某个条目用erase()
erase(iterator it); //通过一个迭代器对象删除
erase(iterator first, iterator last); //删除一个范围
size_type erase(const Key& key); //通过关键字删除,删除了会返回1,否则返回0
clear()就相当于 enumMap.erase(enumMap.begin(), enumMap.end());
4、遍历
map不能直接用下标进行遍历,因为用下标则表示输入的为关键字,无法遍历,一般用迭代器来实现:
map<string,int> m;
map<string,int>::iterator it;
it = m.begin();
while(it != m.end())
{
//it->first;
//it->second;
it ++;
}
5、其他函数
begin() 返回指向map头部的迭代器
clear() 删除所有元素
count() 返回指定元素出现的次数
size() 返回map中元素的个数
swap() 交换两个map
empty() 如果map为空则返回true
end() 返回指向map末尾的迭代器
get_allocator() 返回map的配置器
max_size() 返回可以容纳的最大元素个数
rbegin() 返回一个指向map尾部的逆向迭代器
rend() 返回一个指向map头部的逆向迭代器
注意:C++ map中key不要使用指针,请直接使用对象。因为如果使用指针的话用函数find查找时找到的是指针,而不是指针指向的值,除非重载查找操作符;
参考:C++ map的基本操作和使用
C++中map容器的说明和使用技巧
二、set
set的应用和map有些类似,不过set每一个元素只有关键字,没有对应的值。set的建立:set<int> a
,set<int,greater<int>> s
,其中第二个为建立一个有大到小排序的set,(greater在头文件functional中),默认set是由小到大排序的,和map一样。
1、插入数据
set可以在定义时用数组初始化,也可以使用insert()函数来进行数据添加,set插入相同的数据时不会有效。
int a[] = {1,3,5};
set<int> s(a,a+3); //数组初始化
set<int> d;
d.insert(3); //insert 插入
d.insert(3); //d中已经插入了3,不会插入
2、查找数据
set中查找数据使用find()函数,返回的是对应的迭代器。遍历set中的数据一般是使用迭代器的。
set<int> s;...
s.find(2) != s.end() //查找到
3、删除数据
删除数据使用erase函数,主要有下面3种用法,和map是一样的
erase(iterator) //删除定位器iterator指向的值
erase(first,second) //删除定位器first和second之间的值
erase(key_value) //删除键值key_value的值
4、遍历
set和map一样,不支持下标访问,只能使用迭代器进行遍历访问;
set<string> sstr;
set<string>::iterator it;
it = sstr.begin();
while(it!=sstr.end()){
cout << *it << endl;
it++;
}
5、其他函数
begin() //回set容器的开始迭代器
end() //返回set容器的末尾迭代器
clear() //删除set容器中的所有的元素
empty() //判断set容器是否为空
max_size() //返回set容器可能包含的元素最大个数
size() //返回当前set容器中的元素个数
参考: STL中的set容器的一点总结 。
三、multimap
multimap和map类似,不过multimap可以有重复的键值。multimap的操作和map一样,都是通过insert来插入数据,不过不能像map那样支持关键字访问,查找元素也是使用find,返回第一个找到的元素迭代器。multimap还有一个函数count,用于统计相同键值的数量。只能通过迭代器访问所有元素。
#include <map> //都在这个文件中
...
struct st{...}; //st重载了<,也可以重定义仿函数
int main()
{
multimap<st,int> da;
map<st,int>da2;
st s1(2); st s2(4);
st s3(2); st s4(1);
da.insert(pair<st,int>(s1,1));
da.insert(pair<st,int>(s2,2));
da.insert(pair<st,int>(s3,3));
da.insert(pair<st,int>(s4,4));
da2[s1] = 1; da2[s2] = 2; //map才能这样用关键字来访问
da2[s3] = 3; da2[s4] = 4; //map可以和上面一样用insert
int i = da.count(s3); //multimap 计算关键字和s3相同的有几个
return 0;
}
四、multiset
multiset和set类似,但是可以有相同的关键字,当set进行insert插入时重复的不会插入,但是multiset会,其它的两者应用相同,使用count可以计算相同关键字的个数,实际上,map和set也支持count函数,只不过存在返回1,没有返回0。
#include <map> //都在这个文件中
...
struct st{...}; //st重载了<,也可以重定义仿函数
int main()
{
multiset<st> da1;
set<st> da3;
st s1(2); st s2(4);
st s3(2); st s4(1);
da1.insert(s1); da1.insert(s2);
da1.insert(s3); da1.insert(s4);
da3.insert(s1); da3.insert(s2);
da3.insert(s3); da3.insert(s4);
int x = da1.count(s3);
int j = da3.count(s3);
return 0;
}
上面的代码中都使用了自定义结构,在结构中重载了符号<;当然不管是哪种结构set,map,multiset,multimap都支持自定义仿函数,可以在创建相应的数据结构时指定对应的仿函数,这样就可以实现同样的功能了。