一. 关联式容器
在初阶阶段,我们已经接触过STL中的部分容器,比如:vector、list、deque、
forward_list(C++11)等,这些容器统称为序列式容器,因为其底层为线性序列的数据结构,里面存储的是元素本身。那什么是关联式容器?它与序列式容器有什么区别?
关联式容器也是用来存储数据的,与序列式容器不同的是,其里面存储的是<key, value>结构的键值对,在数据检索时比序列式容器效率更高
二. 键值对
用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量key和value,key代表键值,value表示与key对应的信息
举例子:
现在要建立一个英汉互译的字典,那该字典中必然有英文单词与其对应的中文含义,而且,英文单词与其中文含义是一一对应的关系,即通过该应该单词,在词典中就可以找到与其对应的中文含义
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) {} };
三. C++中的Set
1️⃣Set的介绍
Set本质就是Key的模型,就是确认该值在不在
2️⃣Set的使用(参照文档)
Set支持的操作是增删查,不能改!(因为底层是一颗搜索树,改了就乱了)
🌈set的模板参数列表
三个模板参数:
T:set中存放元素的类型,实际在底层存储<value, value>的键值对
Compare:仿函数;set中元素默认按照小于来比较(如果比较的方式不满意,可以自己去控制比较规则:自己写仿函数)
Alloc:set中元素空间的管理方式,使用STL提供的空间配置器 ( 内存池)
注意:在使用set时,需要包含头文件set
🌈set的构造
拷贝都是深拷贝,要拷贝一棵树,代价很大
void testset2() { set<int> set1;//空构造 int num[] = { 1, 2, 3, 7, 9, 3, 10, 1 }; //区间构造 set<int> set2(num, num + sizeof(num) / sizeof(num[0])); //拷贝构造 set<int> set3(set2); for (auto& e : set3) //打印结果看出set可以去重 { cout << e << " "; } cout << endl; }
🌈set的迭代器
此处和之前的容器差不多,所以就省略过,直接看图
函数说明 功能介绍
begin + end(重点) 获取第一个数据位置的, 获取最后一个数据的下一个位置的
cbegin() const 和 cend()const 无非就是针对const的版本,不可写
rbegin + rend 获取最后一个数据位置,获取第一个数据前一个位置
反向迭代器 同理
void test_set() { //set<int> s; //s.insert(1); //s.insert(2); //s.insert(3); set<int> s = { 1, 2, 1, 6, 3, 8, 5 }; //排序 + 去重 set<int>::iterator it = s.begin(); while (it != s.end()) { cout << *it << " "; ++it; } cout << endl; //支持迭代器也就支持范围for了 for (auto e : s) { cout << e << " "; } cout << endl; }
如果我要整成降序的呢?
反向迭代器
仿函数: less—>greater
int a[] = { 1, 2, 1, 6, 3, 8, 5 }; set<int, greater<int>> s(a, a + sizeof(a) / sizeof(int));
🌈set的常见修改操作
🥑find & erase
普通的寻找和删除当然没有什么问题!
但是特殊的呢?
我删除一个不存在的值呢?会怎么样?
所以写完find要判断一下是否真正的找到了,在才删除
set<int>::iterator pos = s.find(20); if (pos != s.end()) { s.erase(pos); }
🥑count
但是count不是为此设计的!是为了和multiset保持接口的一致性,所以都设计了
提一嘴
🥑lower_bound 和 upper_bound
我想把某个范围的值都找到!
lower_bound :下限的意思,返回 >= val的值 upper_bound:上限的意思,返回 > val的值 itlow = myset.lower_bound(35);//返回大于等于35的值 itup = myset.upper_bound(60);//返回大于60的值
3️⃣Multiset的用法
multiset容器与set容器实现和接口基本一致,唯一区别就是,multiset 允许键值冗余,即multiset容器当中存储的元素是可以重复的
代码展示:
void testset4() { int a[] = { 1, 2, 1, 6, 3, 8, 5 }; //允许键值冗余 multiset<int> s(a, a + sizeof(a) / sizeof(int)); for (auto e : s) { cout << e << " "; } cout << endl; }
结果展示:
键值冗余之后,我们的find该怎么样找数据呢?
find时,如果有多个值,返回中序的第一个
void testset4() { int a[] = { 1, 2, 1, 6, 3, 8, 5, 3}; //允许键值冗余 multiset<int> s(a, a + sizeof(a) / sizeof(int)); //find时,如果有多个值,返回中序的第一个 auto pos = s.find(3); while (pos != s.end()) { cout << *pos << " "; ++pos;//这里的++ ,就是加到下一个的3的位置 } cout << endl; }
当然如果是要删除erase3的时候,肯定是删除所有的3!