文章目录:
一、关联容器简介
(一)基本概念
关联容器也是存储数据的容器,但是和顺序容器有很大的区别。
【关联容器底层数据结构:】
底层存放红黑树。
- BST:二叉搜索树,二叉排序树:保证中序遍历排列升序有序。所以在插入结点时,需要调整结点。
- 红黑树:是一种特殊的BST树,把结点划分为红节点和黑节点,进行调整。
【关联容器分类:】
- set:单集合容器
- multiset:多集合容器
- map:单映射容器
- multimap:多重映射容器
(二)关联容器都有的函数
【构造函数】
- 默认的构造:直接开辟空间。如set<int> s。
- 传入迭代器(指针)区间的构造函数:传入起始位置,末尾位置,会把起始~末尾的迭代器区间元素传入容器。注意也可以传入数组,字符串的指针。如set<int> s(arr,arr+len),将arr~arr+len区间的数据传入容器。注意map的数组不是一维数组,所以尽量不使用区间构造map。
【其他函数】
函数名称 | 含义 | 使用 |
---|---|---|
find查找函数 | 因为关联容器底层是红黑树,中序遍历有序,可以使用二分查找,所以关联容器实现了自己的find,利用二分查找实现元素,时间复杂度为O(logn),比泛型算法find时间复杂度O(n)速度快。 | set<int>iterator fit=s.find(x);//在s容器中查找元素x |
count计数函数 | 返回关联容器中值为x的元素个数 | int co=s.count(x);//返回x的个数 |
清空函数 | 清空容器元素 | c.clear() |
【类型别名:】
类型别名 | 含义 |
---|---|
key_value | 容器的关键字类型 |
mapped_type | 每个关键字关联的类型,只适用于map |
value_type | 对于set,与key_type相同;对于map,等同于pair<const key_type>,mapped_type> |
迭代器需要进行自加操作,用到it++,++it:
- it++:先使用旧值运算,再++;原理:先对a进行备份 ,产生临时量,内置类型的临时量是常量。整个运算过程中用的都是临时量,直到表达式结束时,把a自加。
- ++it:先自加++后,再运算;原理:用it本身,进行自加,返回it本身
所以it=begin(),it++后,还是指向begin()位置;++it后向前走了一个,指向第二个位置。
二、set
set单集合,存放元素value,不允许重复,不允许修改,按照一定次序存储。 头文件为:
# include<set>
(一)对set容器的操作
1. 增
没有必要提供端点位置的数据插入(前插,尾插),因为尾插后,会将其调整,调整后不一定在最后,所以只需要提供任意位置插入函数即可。插入时不需要传入位置,只需要传入数值即可,因为树形结构会进行调整。
插入方式:
插入方式 | 形式 | 含义 |
---|---|---|
插入元素 | insert(val) | 将元素val插入set,插入后会自动调整排序 |
给指定位置插入元素 | insert(index,val) | 位置无效,只是为了和前面顺序容器兼容,你传入了位置,不一样插入指定的位置,因为存在自动调整 |
插入区间元素 | insert(first,last) | 在set中插入(first,last)区间的元素 |
2. 删
三种方式:
删除方式 | 形式 | 含义 |
---|---|---|
删除区间元素 | erase(first,last) | 删除first~last之间的元素 |
删除指定位置的元素 | erase(index) | 删除set上index上的元素 |
删除元素 | erase(val) | 删除元素val |
3. 访问
可以通过迭代器来访问set容器的元素,但是不能进行修改。
(二)特点
- 不允许数据重复,即key关键字不允许重复,可以去重。
- set的元素不能在容器中修改,因为:元素用const修饰,修改过后不能自己调整红黑树,导致序列乱序。所以修改一个元素可以先删除再插入。
- set在插入元素时,会进行排序,默认按照红黑树中序遍历升序的方式排序, 所以 如果用set存储对象信息,需要在对象对应的类中提供比较方式,因为set在存储数据时,不知道怎么比较对象。
- 基于关键字的快速查询。
(四)演示
# include<iostream>
# include<deque>
# include<vector>
# include<list>
# include<algorithm>
# include<iterator>
# include<set>
template<typename Container>
void show(Container& con)
{
typename Container::iterator it=con.begin();//iterator为从属名称,所以声明类型,否则编译器不知道
for(;it!=con.end();it++)
{
std::cout<<*it<<" ";
}
std::cout<<std::endl;
}
int main()
{
std::set<int> myiset;//无参构造
int a[]={
0,1,2,3,4,5,6,7};
int len=sizeof(a)/sizeof(a[0