用来表示具有一一对应关系的一种数据结构,该结构中只包含两个成员变量key和value,key代表关键字,value表示关键字对应的值。比如:现在要建立一个英译汉的词典,那该词典中必然有英文单词和与其对应的中文含义,而且,英文单词与中文含义是一一对应的关系,即通过该单词,在词典中就可以找到与其对应的中文含义。
SGI-STL中关于pair键值对的定义:
template <class T1, class T2>
struct pair
{
typedef T1 first_type;
typedef T2 second_type;
T1 first;
T2 second;
pair(): first(T1()), second(T2())
{}
pair(const T1& a, const T2& b): first(a), second(b)
{}
};
pair();
构造一个空的pair,其中first和second的值为对应类型的默认值
// 构造一个空的pair
pair<int,int> p;
cout<<p.first<<":"<<p.second<<endl;// 0:0
template
pair (const pair & pr);
拷贝构造相同的pair,内部实现为浅拷贝
pair<int,int> p1;
pair<int,int> p2(p1);// 用p1拷贝构造p2
cout<<p2.first<<":"<<p2.second<<endl;// 0:0
pair (const first_type& a, const second_type& b);
最常用的构造方式,直接传first和second的值
pair<int,string> p(1,"hello world");
cout<<p.first<<":"<<p.second<<endl;// 1:hello world
make_pair构造一个临时对象
底层通过封装构造函数来实现,它可以自动识别我们传入数据的类型,通常用来构造临时对象作为参数传入。
make_pair(1,"haha");
make_pair(2,"hehe");
set是按照一定次序存储元素的容器,它的元素总是按照其内部比较对象(类型比较)所指示的特定严格弱排序准则进行排序,在底层使用红黑树实现。在set中,元素的value也标识它(value就是key,类型为T),并且每个value必须是唯一的。set中的元素不能在容器中修改(元素被const保护),但是可以从容器中插入或删除它们。
pair
insert (const T& val)
功能:插入一个值为val的节点
返回值:返回一个pair
参数:需要存储的key数据
样例:
set<int> s;
s.insert(1);
s.insert(3);
s.insert(2);
for(auto& e : s)
{
cout<<e<<endl;
}
void erase (iterator position);
功能:删除set中position迭代器位置上对应的节点
size_t erase (const T& val);
功能:删除值为val的节点
返回值:删除了的元素的数量
样例:
set<int> s;
s.insert(1);
s.insert(2);
s.insert(3);
for(auto& e : s)
{
cout<<e<<endl;
}
// 删除值为3的节点
s.erase(3);
for(auto& e : s)
{
cout<<e<<endl;
}
iterator find (const T& val) const;
功能:查找值为val的节点
参数:要查找的节点的值
返回值:找到了返回节点的迭代器,找不到返回set::end,即最后一个节点的下一个位置的迭代器。
样例:
set<int> s;
s.insert(1);
s.insert(2);
s.insert(3);
// 查找3这个元素
set<int>::iterator it = s.find(3);
if(it!=s.end())
{
cout<<*it<<endl;// 3
}
multiset相当于set 2.0,只不过其中元素是可以重复的,multi这个前缀的意思“多”,底层实现也是红黑树。
性质上的区别在与set不能存储值相同的元素,而multiset可以。
使用上的差别比如对于insert这个函数:set返回的是一个pair
map是关联容器,它按照特定的次序(按照key来比较),存储由关键字key和值value组合而成的pair键值对。在map中,关键字key通常用于排序和惟一地标识元素,而值value中存储与此关键字key关联的内容。key和value的类型可能相同,也可能不同。
map()
功能:构造一个空的map
map<int double> m1;
map<double,int> m2;
pair
insert (const pair & val);
功能:插入一个键值对val
参数:要插入的pair键值对
返回值:返回一个pair
样例:
// 演示insert
string fruits[]={"西瓜","香蕉","苹果","苹果","西瓜","香蕉"};
map<string,int> m;
// 统计各种水果的数量
for(auto& e : fruits)
{
pair<map<string,int>::iterator,bool> p = m.insert(make_pair(e,1));
if(p.second == false)
{
++(p.first->second);
}
}
// 打印map
for(auto& e : m)
{
cout<<(e.first)<<":"<<(e.second)<<endl;
}
size_t erase (const k& k);
功能:删除关键字key=k的节点
参数:要删除的关键字k
返回值:删除节点的个数
void erase (iterator position);
功能:通过迭代器来删除节点
参数:要删除节点的迭代器
返回值:无
iterator find (const k& k);
const_iterator find (const k& k) const;
功能:查找一个值为k的节点
参数:需要查找的关键字k
返回值:如果找到了,返回该节点的迭代器;如果没找到返回最后一个节点的下一个位置的迭代器,即end()。
样例:
// 演示find
string fruits[]={"西瓜","香蕉","苹果","苹果","西瓜","香蕉"};
map<string,int> m;
// 统计各种水果的数量
for(auto& e : fruits)
{
map<string,int>::iterator it = m.find(e);
if(it!=m.end())
{
++(it->second);
}
else
{
m.insert(make_pair(e,1));
}
}
// 打印map
for(auto& e : m)
{
cout<<(e.first)<<":"<<(e.second)<<endl;
}
v& operator[ ] (const k& k);
功能
PS:我们一般不用[ ] 来查看键值对的value,因为如果没有的话它会自动插入,造成不必要的麻烦。查看的话通常还是用find()。
底层原理
内部其实是对insert()进行了封装,为什么不用find()进行封装?因为find()如果查找失败只是返回一个没有作用的迭代器,自然也拿不到它的value,这与[ ]的特性不匹配(方括号的特性是无论如何都要拿到key所对应的value),而insert()不论插入成功亦或失败都可以节点的迭代器,继而拿到value。
// []底层其实是调用下面这个式子的
(*((this->insert(make_pair(k,mapped_type()))).first)).second
样例:
// 演示[]
string fruits[]={"西瓜","香蕉","苹果","苹果","西瓜","香蕉"};
map<string,int> m;
// 统计各种水果的数量
for(auto& e : fruits)
{
++(m[e]);
}
// 打印map
for(auto& e : m)
{
cout<<(e.first)<<":"<<(e.second)<<endl;
}
multimaps也是关联式容器,它按照特定的顺序,存储由key和value映射成的键值对
在性质上,前者可以存储相同key值的节点(至于value相同与否无所谓),而后者key必须唯一。
在使用上,区别比如insert():前者返回插入节点的迭代器,后者返回pair