前言
map和set是STL模板库中重要的关联式容器,与序列式容器不同的是,关联式容器里面存储的是<key,value>结构的键值对,在数据检索时比序列式容器效率更高。让我们一起来看看吧!
目录
1.set
1.1键值对
1.2set的介绍
1.3set的使用
1.3.1set的模版参数列表
1.3.2set的构造函数
1.3.3set的迭代器
1.3.4与容量相关的
1.3.5set的增删查
2.map
2.1map的介绍
2.2map的使用
2.2.1 map的模版参数说明
2.2.2map的构造
2.2.3map的迭代器
2.2.4增删查
2.2.5容量相关
2.2.6例子
3.multiset
4.multimap
1.set
和其他容器一样set可以进行增删查,但是不能改变它的值,因为它的底层是用平衡搜索树来实现的额,如果将节点的值改变,就会破坏平衡搜索树的性质,因此改变它是非法的。
1.1键值对
键值对是用来表示一一对应关系的一种结构,该结构中包含两个变量成员,key和value,key代表键值,value表示与key一一对应的信息。比如,现在有一本英汉词典,英语单词和其对于的汉语意思构成键值对。
SGI-STL中关于键值对的定义:
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)
{}
};
1.2set的介绍
set的介绍
关于set使注意事项:
1.与map/multimap不同,map/multimap中储存的是真正的键值对<key,value>,set中只放value,但是底层实际上是由<value,value>构成的键值对。
2.set中插入元素时,只需要插入value即可,不需要重构键值对。
3.set中的元素不可重复。
4.使用set迭代器遍历set中的元素实际上平衡树的中序遍历。
5.set中的元素默认是按照小于来比较的。
6.set查找某个元素,时间复杂度为:logN。
7.set的元素不允许修改
8.set底层是由红黑色来实现的
1.3set的使用
1.3.1set的模版参数列表
1.T中存放存放元素的类型,底层实际上存储的<value,value>键值对。
2. Compare:set中的默认元素按照小于来比较的
3.Alloc:set中元素空间的管理方式,使用STL提供的空间配置器管理
1.3.2set的构造函数
函数声明 | 功能介绍 |
set (const Compare& comp = Compare(), const Allocator& = Allocator() ); | 构造空的set |
set (InputIterator first, InputIterator last, const Compare& comp = Compare(), const Allocator& = Allocator() ); | 用[first,last]区间的元素构造set |
set ( const set<Key,Compare,Allocator>& x); | set的拷贝构造 |
1.3.3set的迭代器
与其他容器一样set也可以使用迭代器遍历,并且set只能使用迭代器遍历。
函数声明 | 功能 |
iterator begin() | 返回set起始位置的元素的迭代器 |
iterator end() | 返回set最后一个位置后面的迭代器 |
const_iterator cbegin() const | 返回set起始位置的const迭代器 |
const_iterator cend() const | 返回set最后一个位置后面的const迭代器 |
reverse_iterator rbegin() | 返回set起始位置的反向迭代器,即end |
reverse_iterator rend() | 返回set最后一个元素下一个位置的迭代器,即rbegin |
const_reverse_iterator crbegin() const | 返回set起始位置的反向const迭代器,即cend |
const_reverse_iterator crend() const | 返回set最后一个元素下一个位置的反向const 迭代器,即crbegin |
1.3.4与容量相关的
函数声明 | 功能介绍 |
bool empty ( ) const | 检测set是否为空,返回值是bool值,为空返回true |
size_type size() const | 返回set中有效元素的个数 |
1.3.5set的增删查
函数声明 | 功能介绍 |
void erase ( iterator position ) | 删除迭代器position位置的元素 |
size_type erase ( const key_type& x ) | 删除值为x的元素 |
void erase ( iterator first, iterator last ) | 删除set中[first,last)区间的元素 |
void swap ( set<Key,Compare,Allocator>& st ); | 交换set中的元素 |
void clear ( ) | 将set清空 |
iterator find ( const key_type& x ) const | 返回值为x的迭代器 |
size_type count ( const key_type& x ) const | 返回值为x的元素个数 |
2.map
2.1map的介绍
1.map是关联式容器,它按照特定的次序(按照key值来比较)存储由键值对key和值value组合而成的元素。
2.在map中,key键值对通常用于排序和唯一的标识元素,而值value中存储与此值key关联的内容。键值对key和value的类型可能不同,并且在map内部,key与value通过成员类型value_type绑在一起,为其区别为pair:typedef pair<const key, T> value_type;
3.在内部,map中的元素总是按照键值key进行比较排序的。
4.map通过键值访问单个元素的速度通常比unordered_map慢,但是map允许根据顺序对元素直接迭代(即对map中的元素进行迭代可以得到一个有序序列)。
5.map支持下标访问符,即在[]中放入key,就可以找到与key对应的value。
6.map通过被实现为红黑色。
2.2map的使用
2.2.1 map的模版参数说明
template < class Key, // map::key_type class T, // map::mapped_type class Compare = less<Key>, // map::key_compare class Alloc = allocator<pair<const Key,T> > // map::allocator_type > class map;
key:对应键值对中的key类型。
T:键值对中的value类型
Compare:比较器类型,map中的元素是按照key来比较的,缺省情况下按照小于来比较,一般情况下(内置类型元素)不需要传递参数,如果无法比较时(自定义类型),需要用户自己显示传递比较规则(一般情况下按照函数指针或者仿函数来传递)
Allloc:通过空间配置器来申请底层空间,不需要用户传递,除非用户不想使用标准库提供的空间配置器。
2.2.2map的构造
函数声明 | 功能介绍 |
map | 构造一个空的map |
2.2.3map的迭代器
函数声明 | 功能介绍 |
begin()和end() | begin:首元素的位置,end:最后一个元素下一个元素的位置 |
cbegin()和cend() | 与begin和end的意义相同,但是cbegin和cend所指的元素不能修改 |
rbegin()和rend() | 反向迭代器,rbegin在end位置,rend在begin位置,其++和--都是与begin和end操作相反的移动。 |
crbegin()和crend() | 与rbegin和rend位置相同,操作相同,但是crbegin和crend所指向的不能修改 |
2.2.4增删查
函数声明 | 功能介绍 |
pair<iterator,bool> insert ( const value_type& x ) | 在map中插入一个键值对x,注意x是一个键值对,返回值也是一个键值对,iterator代表新插入元素的位置,bool代表释放插入成功 |
void erase ( iterator position ) | 删除迭代器position位置的元素 |
size_type erase ( const key_type& x ) | 删除键值为x的元素 |
void erase ( iterator first, iterator last ) | 删除[first,last)区间中的元素 |
void swap ( map<Key,T,Compare,Allocator>& mp ) | 交换两个map中的元素 |
void clear ( ) | 将map中的元素清空 |
iterator find ( const key_type& x ) | 在map中查找key值为x的元素,找到返回该元素的位置的迭代器,否则返回end |
const_iterator find ( const key_type& x ) const | 在map中查找key为x的元素,找到返回该元素的位置的const迭代器,否则返回cend |
2.2.5容量相关
函数声明 | 功能简介 |
bool empty ( ) const | 检测map中是否为空,如果为空返回true |
size_type size() const | 返回map中的有效元素的个数 |
mapped_type& operator[] (const key_type& k) | 返回key对应的value |
如果使用operator[]时没有找到key值,即当key不存在时,operator[]用默认的value与key构造键值对然后插入,返回默认的value,at()函数抛出异常。
2.2.6例子
#include<iostream>
#include<map>
#include<set>
#include<string>
using namespace std;
void map1()
{
//使用map来统计水果出现的次数
string s[] = { "西瓜", "西瓜", "菠萝", "西瓜", "苹果", "苹果", "西瓜",
"西瓜", "菠萝", "菠萝", "哈密瓜","甜枣","甜枣","荔枝" };
map<string, int> mp;
for (auto& e : s)
{
map<string, int>::iterator it = mp.find(e);
if (it != mp.end())
{
it->second++;//存在的水果次数就加加
}
else
{
mp.insert(make_pair(e,1));//不存在就插入
}
}
for (auto& e : mp)
cout << e.first << " " << e.second << endl;
}
void map2()
{
map<string, string> m;
//向map中插入元素
//将键值对<"apple","苹果">插入map中,用pair来构造键值对
m.insert(pair<string, string>("apple", "苹果"));
//将键值对<"orange","橙子">插入到map中,用make_pair来构造键值对
m.insert(make_pair("orange", "橙子"));
//用operator[]向map中插入元素
m["pear"] = "梨子";
//key不存在时抛异常
//
cout << m.size();
//遍历map
for (auto& e : m)
cout << e.first << ": " << e.second << endl;
//map中的键值对key一定是唯一的
//如果key存在将插入失败
auto e = m.insert(make_pair("apple", "苹果"));
if (e.second)
{
cout << "<apple,苹果>不在map中, 已经插入" << endl;
}
else
{
cout << "键值为peach的元素已经存在:" << endl;
}
auto e1 = m.erase("apple");//删除键值对为“Apple”的元素
if (e1)
{
cout << "删除apple成功!" << endl;
}
else
{
cout << "删除apple失败!" << endl;
}
}
void maps()
{
string s[] = { "西瓜", "西瓜", "菠萝", "西瓜", "苹果", "苹果", "西瓜",
"西瓜", "菠萝", "菠萝", "哈密瓜","甜枣","甜枣","荔枝" };
map<string, int> m;
for (auto& e : s)
m[e]++;//通过调用map的operator[]来统计水果出现的次数
for (auto& e : m)
cout << e.first << ":" << e.second << endl;
}
可以通过map中的operator[]来对水果出现的次数进行统计,这和其他容器的opreator[]不同,它是怎么做到的呢,这就要和它的底层实现有关系了,实际上operator[]是调用insert实现的,而且operator[]返回的是<K,V>键值对的V的引用。
return (*((this->insert(make_pair(k, mapped_type()))).first)).second
所以当key不存在时会将key插入map对象中,operator[]用默认的value和key组成键值对,然后插入,返回该默认的value。
如果key已经存在不会插入成功,operator[]返回已经存在的<key,vaule>键值对的value的引用。
我们可以使用insert来替代operator[]的功能,如下:
void map3() { string s[] = { "西瓜", "西瓜", "菠萝", "西瓜", "苹果", "苹果", "西瓜", "西瓜", "菠萝", "菠萝", "哈密瓜","甜枣","甜枣","荔枝" }; map<string, int> m; for (auto& e : s) { std::pair<map<string,int>::iterator, bool> it = m.insert(make_pair(e, 1)); if (it.second == false)//key存在 { ++ (it.first->second); } } for (auto& e : m) cout << e.first << ":" << e.second << endl; }
operator[]还可以进行增查改,例如:
void func() { map<string, int> m; m["香蕉"];//增 cout << m["香蕉"] << endl;//查 m["香蕉"] = 5; //插入+修改 }
3.multiset
它和set的用法基本相同,接口也是一致的,但是它允许冗余的键值对存在。例如:
void multiset1()
{
multiset<int> se;
int array[] = { 1,3,3,3,4,5,6,4 };
for (auto& e : array)
{
se.insert(e);
}
for (auto& e : se)
cout << e << " ";
}
4.multimap
它和map的用法也是基本相同的,唯一的区别是multimap允许冗余的键值对存在,并且它没有operator[],因为存在多个相同的key无法区分到key值,因此不提供operator[]。