目录
一,关联式容器
二,键值对
2.1为什么使用键值对
2.2make_pair()
三,STl关联容器
四,set
4.1模板参数
4.2默认构造
4.3使用
去重功能和自动排序
4.4增删查
insert
find
erase
五,multiset
count
erase
find
六,map
6.1默认构造
特性
6.2使用
insert
operator[]
示例
方法1
方法2
七,multimap
一,关联式容器
- 在STL中vector,list,stack,queue等都属于序列式容器,底层是线性结构,里面存储的是元素本身;
- 关联式容器也是用来存储数据的,与序列式容器不同的是,其里面存储的是 <key, value> 结构的键值对,在数据检索时比序列式容器效率更高,set 和 map 便是关联式容器
二,键值对
键值对是用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量key和value;
- key代表键值;
- value表示与key对应的信息 pair - C++ Reference (cplusplus.com)
在 set 和 map 就使用了键值对,这个键值对名为 pair,它是一个 struct 定义的类模板,即可以在外部访问 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就是一个类模板,根据<>里的两个参数来实例化类,第一个参数表示key,第二个表示value。
- pair的两个成员变量first表示key,second表示value。
2.1为什么使用键值对
为什么不直接在容器中定义 key 和 value 变量,而是将 key 、value 合并到 pair 中整体作为一个类型来使用呢?
这是因为 C++ 一次只能返回一个值,如果我们将 key 和 value 单独定义在容器中,那么我们就无法同时返回 key 和 value ;而如果我们将 key 、value 定义到另一个类中,那我们就可以直接返回 pair ,然后再到 pair 中分别去取 first 和 second 即可。
2.2make_pair()
该函数是用来制作一个pair类型的匿名对象的:
make_pair - C++ Reference (cplusplus.com)
map<string, string> dict;
pair<string, string> kv1("sort", "排序");
//三种插入
dict.insert(kv1); //有名
dict.insert(pair<string,string>("left", "左边")); //匿名
dict.insert(make_pair("right", "右边")); //更快速的匿名
make_pair()是为了让我们更加方便的使用键值对。
三,STl关联容器
- STL关联容器有两种结构:树形结构,哈希结构;
- 常见的树形结构关联容器有:map、set、multimap、multiset;
- 这四种容器的共同点是:使用平衡搜索树(即红黑树)作为其底层结果,容器中的元素是一个有序的序列
四,set
set是按照一定次序存储元素的容器,其底层是一棵平衡二叉搜索树 (红黑树);
由于二叉搜索树的每个节点的值满足左孩子 < 根 < 右孩子,并且二叉搜索树中没有重复的节点,所以set可以用来排序、去重和查找,同时由于这是一棵平衡树,所以 set查找的时间复杂度为 O(logN),效率非常高;
- 与map等容器不同,set存储的元素其实只有value,在底层是<value, value> ,
- 所以在插入元素时,只需要提供value即可,不需要构造键值对。使用set的迭代器进行遍历set时,会得到一个有序的序列。这是因为遍历的方式其实是二叉搜索树的中序遍历。
- set中的元素也不允许修改,因为这可能会破坏搜索树的结构,但是 set允许插入和删除。
4.1模板参数
class T:是 set 中存放元素的类型,实际在底层存储 <value, value> 的键值对 ;
class Compare = less<T>:compare是仿函数,set中元素默认按照小于来比较(less);
class Alloc = allocator<T>:控制set的空间管理方式,使用STL提供的空间管理配置器.
4.2默认构造
set::set - C++ Reference (cplusplus.com)
set提供了三种构造:默认空构造,迭代器区间构造和拷贝构造;
set<int> s1;
//迭代器区间构造
s1 = { 1,2,3,4,5 };
set<int> s2(s1.begin(),s1.end());
//拷贝构造
set<int> s3(s2);
4.3使用
去重功能和自动排序
- set具有降重的功能,当插入的数据已经存在时就不会再插入
- 在打印set中的数据时,我们发现打印出来的结果是升序的,在二叉搜索树中,采用中序遍历的方式打印出来的结果就是升序的。
4.4增删查
insert
有三种插入方式,不建议用指定位置插入,有可能会破坏原二叉搜索结构
set::insert - C++ Reference (cplusplus.com)
find
查找容器中是否存在某个特定的元素
- 如果存在,返回该位置所在的迭代器;
- 如果不存在,则返回set的结束位置的迭代器end()。
count 函数与其类似,只不过返回的是1和0,返回的是数字
set::count - C++ Reference (cplusplus.com)
erase
删除指定位置的值;set::erase - C++ Reference (cplusplus.com)
注:
- 第二个重载函数,由于set中没有重复值,所以返回的值就是1。
- 使用迭代器位置删除时,先find找到位置,再erase;
- 使用指定数据的erase时,删除成功返回1,如果不存在则返回0。
- 使用迭代器区间的erase时,将区间内的数据全部删除。
五,multiset
成员函数和set一样,区别在于multiset支持数据重复,set不可以;
multiset - C++ Reference (cplusplus.com)
- set:排序 + 降重
- multiset:排序(不降重)
count
在set中count成员函数和find功能类似,但是在multiset中它就有了它的作用。
multiset::count - C++ Reference (cplusplus.com)
erase
multiset::erase - C++ Reference (cplusplus.com)
multiset中没有100,所以返回值就是0。
find
multiset容器中存在重复元素,使用查找find函数,返回的是中序遍历中第一个元素;
multiset::find - C++ Reference (cplusplus.com)
其它函数基本上set一模一样了
六,map
map和set一样,也是一个关联式容器,底层是二叉搜索树。
map - C++ Reference (cplusplus.com)
- 键值对映射 :map中的元素是一对键值对(pair),每一个key都有一个value对应。
- 自动排序:与set类似,map中的元素在插入的同时会进行排序,默认情况下是key小的排在前面。
- 唯一键:每个键在map中都是唯一的。
- map查找的时间复杂度是O(logn).
- 迭代器支持:支持使用迭代器来遍历map中的元素。本质上是搜索二叉树的中序遍历。
- 底层是用二叉搜索树(红黑树)实现的。
- 可以使用[key]访问对应的value;(operator[])
6.1默认构造
- 使用默认构造函数创建的map是空的。
- 插入键对值时,使用make_pair创建匿名对象更加方便。
特性
- map具有降重功能,和set一样。
- 不能插入相同的键值对,和set一样,map不支持重复数据。
- 不能插入key值相同,val值不同的键值对。
- map中虽然存放的是键值对,但是它的判断逻辑都只看key值,也就是first所表示的变量。
- map也具有排序 + 降重的功能,依据只看key值而不管value值。
6.2使用
insert
- 参数类型 value_type 是 pair<const key_type, mapped_type> 进行 typedef 得到的,也就是说参数是一个键值对,并使用引用传参
- insert 第一个(框起来的)的返回类型为 pair<iterator, bool>
- pair<iterator, bool>第一个iterator是迭代器;
- 第二个是 bool,用于反映是否插入成功,成功返回true,否则返回false
- 如果插入成功(即元素不存在进行插入):返回为 pair<iterator, true>;迭代器返回的是新插入元素位置的迭代器(pair)
- 如果插入失败(即元素已经存在):返回为 pair<iterator, false>,迭代器返回的是已存在元素位置的迭代器(pair);
- map::insert - C++ Reference (cplusplus.com)
operator[]
通过键来访问或插入元素:
- 如果键存在,它将返回对应的值的引用,即返回 Key 值的引用;
- 如果键不存在,它会自动插入一个键值对,其中值部分为默认构造的值,并返回这个新插入值的引用。
注:即使没有为元素分配映射值(即不给T传值,T为空),该元素使用其默认构造函数构造,插入新元素后,这会将容器大小增加1;
map::operator[] - C++ Reference (cplusplus.com)
- at 成员函数功能与 [] 类似,但是在具有键的元素存在时具有相同的行为(即查找的元素 Key 是存在的时候,at 和 [] 的功能是一样的);
- 但当不存在时抛出异常(即查找的 Key 不存在,[] 的功能是把这个 Key 直接插入map中,但是 at 是抛异常,不会进行插入);
示例
计算水果数量
方法1
方法2
总结:
- [] 的功能是 查找+修改+插入 (修改的原因是 [] 返回 mapped_type(T)值的引用)
- at 的功能是 查找+修改(不支持插入)
七,multimap
multimap和map的不同就是:
- map中的key是唯一的,而multimap中key是可以重复的
multimap中没有重载 operator[] 操作,因为 multimap的 key可能不唯一;(multimap不支持[key]操作);
使用时与map包含的头文件相同