6-6:STL之map和set
Posted 快乐江湖
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了6-6:STL之map和set相关的知识,希望对你有一定的参考价值。
文章目录
前言
(1)序列式容器和关联式容器
- 序列式容器:前面的vector,list等均为序列式容器,特点就是其底层结构为线性结构
- 关联式容器:与序列式容器不同,关联式容器内存储的是键值对,也即<key,value>结构,这样就一维这关联式容器检索数据的效率要远远高于序列式容器
(2)树形结构的关联式容器
STL中共有两种不同结构的关联式容器(适用于不同的应用场景):树型结构与哈希结构
其中树形结构又分为四种:map
,set
,multimap
,multiset
,这四种结构使用红黑树(平衡搜索树)作为底层结构,容器中的元素是一个有序的序列。
一:set
(1)基本介绍
- set是采用一定次序来存储元素的容器;
- 在set中,一个元素的值就代表了这个元素(value就是key,类型为T),并且每个value必须是唯一的(数学中集合的互异性);
- 在set内部,元素总是按照其内部比较对象(由仿函数控制)所指定的特定严格弱排(strict weak ordering)准则进行排序;
- set通过key访问单个元素的速度通常要比
unorderer_set
容器慢,但它们允许根据顺序对子集进行直接迭代; - set在底层使用平衡搜索树实现的(红黑树)
(2)注意
- map/multimap中存放是键值对
<key,value>
,而set中只放value
(但其底层实际上是<value,value>
构成的键值对) - set中插入元素时,只需要插入value即可,不需要构造键值对
- set中的元素不可以重复,所以可以使用set进行去重
- 使用set的迭代器遍历set中的元素,得到有序序列
- set中的元素默认按照小于的方式比较(可以通过仿函数控制)
- set中查找某个元素的时间复杂度为log2n
- set中元素不允许修改
(3)set的使用
使用set需要引入头文件
#include <set>
A:set的模板参数列表
template<
class T;set中存放的数据类型,本质为<value,value>的键值对
class Compare=less<T>;仿函数,set中元素默认按照小于的方式比较
class Alloc=allocator<T>;空间配置器
> class set;
B:set的常用接口
函数声明 | 接口作用 |
---|---|
bool empty() const | 判断set是否为空 |
size_type size() const | 返回set中有效元素的个数 |
pair<iterator,bool> insert(const value type& x) | 在set中插入元素x,实际插入了<x,x>的键值对,如果成功,返回<位置,true>,失败则返回<位置,false> |
void erase(iterator position) | 删除某位置元素 |
size_type erase(const key_type& x) | ,删除set中值为x的元素,返回删除元素个数 |
void erase(iterator first,iterator last) | 删除迭代器区间内的元素 |
void clear() | 将set清空 |
void swap(set<k,c,a>& st) | 交换set中的元素 |
iterator find(const key_type& x)const | 返回set中值为x的元素的位置 |
sizet_type count(const key_type& x) const | 统计set中值为x的元素的个数 |
C:set的使用举例
1:使用一数组,以一定范围构造set,数组内有重复元素
#include <iostream>
#include <set>
using namespace std;
int main()
{
int array[] = { 19,11,3,3,3,5,5,7,9 };
set<int> test_set(array, array + sizeof(array) / sizeof(array[0]));
cout << "set中有效元素个数为" << test_set.size() << endl;
auto it = test_set.begin();
while (it != test_set.end())
{
cout << *it << " ";
++it;
}
cout << endl;
cout << "set中3出现了" << test_set.count(3) << "次" << endl;
}
- 可以用于构造set的数组array中的元素不仅是无序的,并且还有多个重复元素,但是在set中却是有序输出并且没有重复元素,如果换成multiset,则不会去重,只会排序
2:构造一个空的set,然后不断插入
void test2()
{
set<int> test_set;
test_set.insert(9);
test_set.insert(8);
test_set.insert(8);
test_set.insert(8);
test_set.insert(7);
test_set.insert(7);
test_set.insert(6);
for (auto e : test_set)
{
cout << e << " ";
}
cout << endl;
}
- 需要注意的是,虽然算法模块的find和set的成员函数的find效果一样的,但是效率却是千差万别,因为二叉搜索树的效率可以达到log2n
二:map
(1)基本介绍
-
map按照特定的次序(依据key来比较)来存储由键
key
和值value
所组合而成的元素,这种元素称为pairt
即typedef pair<const key,T value> value_type
-
map中的
key
用于唯一的标识元素和排序,value
存储的则是与key
对应或关联的内容。key
和value
的类型可以不同。 -
map中通过键值访问单个元素的速度通常要比unordered_map慢,但是map允许根据顺序队元素进行直接迭代
-
map支持下标访问,也就是
[]
运算符,如果在[]中放入key,返回的结果就是与key对应的value -
map实现为平衡搜索树(红黑树)
(2)键值对
键值对本质也是一种结构,用来表示数据与数据之间一一对应的关系,该结构中一般只包含两个成员变量key和value,key为键,value为键所对应的值。生活中常见的英文单词和中文含义(大多数情况)就是典型的键值对。
STL中(SGI版本)关于键值对的定义如下
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)
{}
};
(3)map的使用
使用map时需要引入头文件
#include <map>
A:map的模板参数列表
template<
class key;//键值对中key的类型
class T;//键值对中value的类型
class compare=less<key>;//仿函数,一般依据key,按照小于来比较
class alloc=allocator<pair<const key,T>>;//空间配置器
>
B:map的常用接口
函数声明 | 接口作用 |
---|---|
bool empty() const | 判断map是否为空 |
size_type size() const | 返回set中有效元素的个数 |
mapped_type& operator[](const key_type& k) | 返回key对应的value |
pair<iterator,bool> insert(const value type& x) | 在map中插入键值对<key,value> |
void erase(iterator position) | 删除某位置元素 |
size_type erase(const key_type& x) | 删除键为x的元素 |
void erase(iterator first,iterator last) | 删除迭代器区间内的元素 |
void clear() | 将map清空 |
void swap(set<k,t,c,a>& st) | 交换两个map |
iterator find(const key_type& x)const | 返回map中key为x的元素的位置 |
sizet_type count(const key_type& x) const | 返回map中key为x的个数,由于key是唯一的,因此其返回值要么是0,要么是1,可以用于判断一个key是否在map当中 |
C:map使用举例
1:构造一个空的map,然后不断insert,由于插入的元素是一个类,所以可以使用匿名对象;然后访问键值对,使用迭代器访问时,访问的是一个结构体,其中结构体的第一个元素first代表key,第二个元素second代表value
void test3()
{
map<string, string> m;
m.insert(pair<string, string>("melon", "西瓜"));
m.insert(pair<string, string>("pitaya", "火龙果"));
m.insert(pair<string, string>("grapefruit", "柚子"));
m.insert(pair<string, string>("Cherry", "樱桃"));
map<string, string>::iterator it = m.begin();
while (it != m.end())
{
cout << "英文中" << it->first << "对应的中文意思是:" << it->second << endl;
it++;
}
cout << "===========================================================================" << endl;
for (auto& e : m)
{
cout << "英文中" << e.first << "对应的中文意思是:" << e.second << endl;
}
}
- 需要注意的是除了可以使用
pair<string,string>("melon","西瓜")
也就是匿名对象传参时,也可以使用make_pair("melon","西瓜")
,这样写更加方便。
2:有一个string数组,里面含有多个string,每个string表示一种水果,其中有些string是重复的,统计出有多少种水果,并且每个水果各有多少个
void test4()
{
string fruits[] = { "苹果","樱桃","苹果","香蕉","苹果","樱桃","梨儿","火龙果","香蕉" };
map<string, int> each_fruit_number;
for (auto& e : fruits)
{
auto ret = each_fruit_number.find(e);//先找是否在map中存在过,也就是是否存在键为e的键值对
if (ret != each_fruit_number.end())//说明存在
{
ret->second++;//相应水果数目增加
}
else
{
each_fruit_number.insert(make_pair(e, 1));//如果不存在就增加一种水果,初始数量为1
}
}
cout << "一共有" << each_fruit_number.size() << "种水果" << endl;
for (auto& e : each_fruit_number)
{
cout << e.first << "共有:" << e.second << "个" << endl;
}
}
以上是关于6-6:STL之map和set的主要内容,如果未能解决你的问题,请参考以下文章