您的位置:首页 > 编程语言 > C语言/C++

C++:关联容器(pair、map、set)

2016-02-29 10:22 375 查看
关联容器和顺序容器的本质区别:

关联容器是通过键存取和读取元素、顺序容器通过元素在容器中的位置顺序存储和访问元素。

两个基本的关联容器类型是map和set。

map的元素以键-值对的形式组织:键用作元素在map的索引,而值则表示所存储和读取的数据。set仅包含一个键,并有效地支持关于某个键是否存在的查询。

set和map类型的对象不允许为同一个键添加第二个元素。如果一个键必须对应多个实例,则需使用multimap或mutiset类型,这两种类型允许多个元素拥有相同的键。

1. pair类型

pair类型的初始化

在头文件
utility
中:

pair<T1,T2> p1;


创建一个pair对象,两个元素的类型分别是T1,T2类型,采用初值进行初始化

pair<T1,T2> p1(v1,v2);


创建一个pair对象,两个元素的类型分别是T1,T2类型,采用v1,v2分别进行初始化

make_pair(v1,v2);


以v1、v2的值创建一个pair对象,类型分别是v1、v2的类型

p.first


返回p中第一个公有数据成员

p.second


返回p中第二个公有数据成员

2. map关联数组

2.1 map初始化

map<k,v>   m1


创建一个名为m1的空的map对象,其键和值的类型分别为k、v

map<k, v>  m(m2)


创建m2的副本m,m与m2的类型必须有相同的键类型和值类型

map<k,v>   m(b,e)


创建map类型的对象m,存储迭代器b和e标记范围内所有元素的副本,元素的类型必须转换为pair

2.2 map定义的类型

map<K,V>::key_type
:在map中键的类型

map<K,V>::mapped_type
:在map中键所关联的值的类型

map<K,V>::value_type
:一个pair类型,它的first元素具有
const map<K,V>::key::type
类型,而second元素则为
map<K,V>::mapped_type
类型

map迭代器进行解引用将产生pair类型的对象,first是键,second是值,:

map<string,int>::iterator map_it = ord_count.begin();
cout<<map_it->first<<""<<map_it->second<<endl;


2.3 给map添加成员

使用下标访问map对象:在map中查找键值为x的元素。如果找到则返回它的值(类型是
map<k,v>::mapped_type
),否则插入一个新的对象,键值为x,值为
map<k,v>
中v的默认初值。

因此,使用下标访问map与使用下标访问数组或vector的行为不同,用下标访问不存在的元素将导致在map容器中添加一个新的元素,它的键即为该下标值。这一特性可以使程序简练:

int main()
{
string str;
map<string,int> wordCount;
while(cin>>str)
{
++wordCount[str];
}

map<string,int>::iterator it_map = wordCount.begin();
cout<<"word"<<"\t\t"<<"count"<<endl;
for(;it_map != wordCount.end();++it_map)
cout<<it_map->first<<"\t\t"<<it_map->second<<endl;
return 0;
}


2.4 使用insert对map进行插入

m .insert(e)


e是一个用在m上的value_type类型的值,如果e.first不在m中则插入一个值为.second的新元素,否则,即该键值在m中已经存在则保持不变,该函数返回一个pair新类型,包含一个指向键值为e.first的元素的map迭代器,以及一个bool类型的对象,表示是否插入该元素

m.insert(beg,end)


插入beg、end标记范围内的元素,如果该元素的m.first已经存在则不插入,否则插入。返回void类型。

m.insert(iter,e)


如果e.first不在m中,则创建新元素,并以迭代器iter为起点搜索新元素的存储位置,否则返回一个迭代器,指向m中具有给定键的元素。

//用insert方法重写单词统计程序
map<string,int> word_count;

word_count.insert(map<string,int>::value_type("aaa",1));
map<string,int> word_count;
string word;
while(cin>>word)
{
pair<map<string,int>::iterator,bool> ret=word_count.insert(make_pair<string,int>(word,1));
if(!ret.second)//如果没插入成功,证明原来已经存在键值,将统计值+1
{
++ret.first->second;// first是一个迭代器,指向插入的键
}
}


2.5 查找和读取map中的元素:

m.count(k)


返回k在m中出现的次数,在map中只是返回0、1(即存在或不存在)

m.find(k)


如果k在m中的键值存在,则返回相应的迭代器,否则返回超出末端的迭代器

//读取元素而又不插入新元素
int occurs;
map<string,int>::iterator it= word_count.find("foobar");//不存在,则返回end迭代器
if(it!=word_count.end())//可能找不到
{
occurs=it.second;
}


2.6 从map中删除元素

使用erase,与顺序容器功能一样:

m.erase(k)


删除m中键为k的元素。返回值为被删除元素的个数,对于map容器而言,其值必然是0或1。

m.erase(p)


从m中删除迭代器p所指向的元素。返回值为void类型。

m.erase(b,e)


从m中删除一段由一对迭代器限定范围的元素。返回值为void类型。

//map对象的迭代遍历:

map<string,int> word_count;

map<string,int>::const_iterator iter = word_count.begin();
while(iter!=word_count.end())
{
cout<<iter->second<<endl;
iter++;
}


2.7 map操作函数总结

//初始化
map<k,v>   m1;//创建一个名为m1的空的map对象,其键和值的类型分别为k、v
map<k, v>  m(m2);//创建m2的副本m,m与m2的类型必须有相同的键类型和值类型
map<k,v>   m(b,e);//创建map类型的对象m,存储迭代器b和e标记范围内所有元素的副本,元素的类型必须转换为pair<const k, v>

//添加元素
m .insert(make_pair(a,b));//如果a不在m中则插入一个值为b的新元素,否则保持不变。
m[a]=b;//该方式下,如果a键不存在,则创建一个<a,b>,否则用b覆盖a键的值

//count或find查找元素
m.count(k);//返回k在m中出现的次数,在map中只是返回0、1(即存在或不存在)
m.find(k);//如果k在m中的键值存在,则返回相应的迭代器,否则返回m.end()

//erase删除元素
m.erase(k);//删除m中键为k的元素。返回值为被删除元素的个数,对于map容器而言,其值必然是0或1。
m.erase(iter);//删除m中迭代器iter指向的元素

//清空map
m.clear();

//map的大小
int mSize=m.size();

//map的遍历
//正向迭代器方式
map<int, string>::iterator  iter;
for(iter = m.begin(); iter != m.end(); iter++)
{
cout<<iter->first<<'  '<<iter->second<<end;
}
//反向迭代器方式
map<int, string>::reverse_iterator  iter;
for(iter = m.rbegin(); iter != m.rend(); iter++)
{
cout<<iter->first<<'  '<<iter->second<<end;
}


3. set类型

set只有键,没有值,所以它的
vaule_type
不是pair类型,而是
key_type
类型。set也支持以上map的一系列操作,如
insert、find、count、erase
等。

//初始化
set<int> s0 ;//创建一个名为s0的空的set对象
set<int, greater<int>> s1 ;//创建一个带大于比较器的set, 默认是小于比较器less<int>
int a[3] = {1, 2, 3} ;
set<int> s2(a, a + 3) ;//用数组初始化一个set
set<int> s2(s1) ;//用拷贝构造函数初始化set,s2是s1的副本
set<int> s2(s1.begin(), s1.end()) ;//创建set类型的对象s2,并用两个迭代器所决定区间内的元素初始化

//添加元素
s.insert(a) ;//如果a不在s中则添加a,否则保持不变。
s.insert(s1.begin(), s1.end()) ;//使用迭代器,批量添加元素

//count或find查找元素
s.count(k);//如果s中存在k,则返回1,否则返回0
s.find(k);//如果k在s中存在,则返回相应的迭代器,否则返回s.end()

//erase删除元素
s.erase(2);//删除键为2的元素
s.erase(iter);//删除迭代器iter指定的元素
s.erase(s.begin(), s.end()) ;//删除s内的所有元素

//清空set
s.clear();

//set的大小
int sSize=s.size();

//遍历
//正向迭代器方式
set<int>::iterator  iter;
for(iter = s.begin(); iter != s.end(); iter++)
{
cout<<*iter<<end;
}
//反向迭代器方式
set<int>::reverse_iterator  riter;
for(riter = s.rbegin(); riter != s.rend(); riter++)
{
cout<<*riter<<end;
}


4. list、set和map的区别和联系

三者都是有序的。

list和set都是单列集合,他们有一个共同的父接口—collection。list是依次列出一个结合中的所有的元素,若集合中有重复的,同样列出,有序;set列出的集合中是不允许有重复的,也就是说里面有一个A对象和一个B对象,若是A.equals(B)==ture,那么用set方法列出的只会有一个,set集合默认是有序的,正向排序。一般遍历set里面的元素时使用iterator。

map <key,value>
是一个双列的集合,里面有一个key,和一个value,其中value是真正存储值的变量。map存储的数据也是有序的,根据键(key)排序。其键(key)不能重复,但是其值(value)是可以重复的。

比如说:

你需要存某门课程全班同学的成绩,就需要用到map,因为每个人的键(姓名)不一样,值(成绩)也不一样。而如果你要统计这门课的作业提交情况,就可以用set,因为你只需要存储键(姓名),一个同学只有交了(true)和没交(false)两种情况。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: