STL关联容器:Set/Multiset与Map/Multimap详解

一、序列式容器和关联式容器

我们已经接触到了不少的容器了,如string,vector,list,deque等,这些容器统称为序列式容器因为逻辑结构为线性序列的数据结构,两个位置存储的值之间一般没有紧密的关联联系比如交换一下数据,它依旧是序列式容器

关联式容器也是存储数据的,与序列式容器不同的是关联式容器逻辑结构通常是非线性结构,两个位置有紧密的关联联系交换一下,它的存储结构就被破坏了关联式容器有 map/set系列和unordered_map和unordered_set系列

map和set的底层是红黑树,红黑树是一棵平衡二叉搜索树。set是key搜索场景的结构,map是key、value搜索场景的结构

二、set

1. set的理性认识

set是一种存储唯一元素并按特定顺序排列的容器

在set中,元素的值同时充当其标识符,并且每一个值都是唯一的在set容器中元素的值不能被修改,但是它们可以从容器中插入和删除元素

T就是set底层关键字的类型默认按照小于比较,如果不符合需求,可以自己传入一个仿函数对象

set底层存储数据的内存是从空间配置器申请的如果需要可以自己实现内存池,传给第三个参数

一般情况下,不需要传入后两个模板参数

set的底层是红黑树实现的,增删查的效率是O(logN),迭代器遍历走的是搜索树的中序,所以是有序的

2. set的接口介绍

cpp 复制代码
//无参的默认构造
set();
//全缺省的默认构造,comp仿函数对象,alloc内存池对象
explicit set (const key_compare& comp = key_compare(),const allocator_type& alloc = allocator_type());
//用一段迭代器区间去构造
template <class InputIterator>
set (InputIterator first, InputIterator last,const key_compare& comp = key_compare(),const allocator_type& = allocator_type());
//拷贝构造
set (const set& x);
//用初始化列表构造
set (initializer_list<value_type> il,const key_compare& comp = key_compare(),const allocator_type& alloc = allocator_type());
//赋值运算符重载
set& operator= (const set& x);


3. iterator

cpp 复制代码
//无论是哪一种迭代器,都不能通过迭代器修改元素
//普通迭代器
//begin返回的是一个指向set容器中第一个元素的迭代器
iterator begin();
const_iterator begin() const;
//end返回的是一个指向set容器中最后一个元素之后的位置的迭代器
iterator end();
const_iterator end() const;
//反向迭代器
//rbegin返回的是指向容器中最后一个元素的反向迭代器
reverse_iterator rbegin();
const_reverse_iterator rbegin() const;
//返回的是一个指向set容器中首个元素前一个理论元素的反向迭代器
reverse_iterator rend();
const_reverse_iterator rend() const;


可以看到,set容器的迭代器是一个双向迭代器

4. capacity

cpp 复制代码
//判空
bool empty() const;
//返回的是set容器中元素的个数
size_type size() const;

5. modifiy

cpp 复制代码
//插入一个val值
pair<iterator,bool> insert (const value_type& val);
//在pos位置插入一个val(pos位置是一个参考位置)
//这个函数可以起到性能优化,因为不用直接从根节点开始搜索,但
//是插入的位置必须是合格的,否则,该行为可能未定义,也可能导
//致程序崩溃,或者损坏数据结构
//所以,该函数有一定的危险性,建议少用
iterator insert (const_iterator position, const value_type& val)
//插入一段迭代器区间
template <class InputIterator>
void insert (InputIterator first, InputIterator last);
//插入一个初始化列表
void insert (initializer_list<value_type> il);
//删除迭代器pos位置的元素
iterator  erase (const_iterator position);
//删除val指定的元素
size_type erase (const value_type& val);
//删除迭代器区间包含的所有的元素
iterator  erase (const_iterator first, const_iterator last);
//交换两个set容器对象的内容
void swap (set& x);
//删除set容器中所有的元素
void clear() noexcept;
//返回一个在容器中使用的比较对象的拷贝,默认情况下,是一个less对象
key_compare key_comp() const;
//在set容器中,key_comp和value_comp是等价的
value_compare value_comp() const;





6. operations

cpp 复制代码
//如果找到的话,返回一个指向和val相等的元素的迭代器,否则,返回set::end()
const_iterator find (const value_type& val) const;
iterator find (const value_type& val);
//返回在set容器中和val元素相等的元素的个数
//由于set容器中所有的元素都是唯一的,因此该函数的返回值只有0或者1
size_type count (const value_type& val) const;
//返回一个迭代器,该迭代器指向在set容器中第一个不小于val的元素
iterator lower_bound (const value_type& val);
const_iterator lower_bound (const value_type& val) const;
//返回一个迭代器,该迭代器指向在set容器中第一个大于val的元素
iterator upper_bound (const value_type& val);
const_iterator upper_bound (const value_type& val) const;
//返回的是在set容器中和val值相等的元素的区间范围
//由于set容器中所有的元素都是唯一的,所以这个范围最多只包含一个元素
//如果没有匹配到,这个范围的长度为0,这两个迭代器指向val之后的第一个元素
pair<const_iterator,const_iterator> equal_range (const value_type& val) const;
pair<iterator,iterator> equal_range (const value_type& val);


算法库里也有一个find函数,set里也有一个find函数,那么这两个find函数有什么区别呢

算法库里的


可以看到,算法库里的find函数是基于迭代器进行查找的,也就是暴力查找,一个一个去遍历

而set里的find函数是基于二叉搜索树的规则进行查找,查找值比当前节点值大,往右子树查找,比当前节点值小,往左子树查找。只需要查找高度次(O(logN))

7. multiset和set的差异

multiset也是一种按照特定顺序存储元素的容器,但是它允许插入多个重复的元素(数据冗余)

multiset和set的差异在于以下几个函数:insert、find、count、erase

insert函数支持值冗余,find函数会返回中序的第一个,count函数返回查找值实际的个数,erase删除所有指定的值


三、map

map也是一个关联式容器,它的存储元素包含 key value和mapped value,它也是按照特定的顺序排序的

在map中,key value通常是用来排序的并且作为唯一的标识符标识该元素,而mapped value是key value关联的存储内容。key value和mapped value组合在一起形成一个新的类型value_type,其实就是pair类型

key value就是第一个模板参数,mapped value就是第二个模板参数

首先在学习map之前,需要了解pair类型。

该类将一对可能类型不同(T1和T2)的值组合在一起,可通过它的公有成员 first 和 second 访问各个值

T1就是 first成员的类型, T2就是 second成员的类型

cpp 复制代码
//无参的默认构造
pair();
//泛化拷贝构造
template<class U, class V> pair (const pair<U,V>& pr);
//初始化构造
pair (const first_type& a, const second_type& b);
//用x设置pair的第一个元素,y设置它的第二个元素
template <class T1, class T2>
pair<T1,T2> make_pair (T1 x, T2 y);

1. map的构造

cpp 复制代码
//全缺省的默认构造
explicit map (const key_compare& comp = key_compare(),const allocator_type& alloc = allocator_type());
//用一段迭代器区间构造
template <class InputIterator>
map (InputIterator first, InputIterator last,const key_compare& comp = key_compare(),const allocator_type& = allocator_type());
//拷贝构造
map (const map& x);
//用初始化列表去构造
map (initializer_list<value_type> il,const key_compare& comp = key_compare(),const allocator_type& alloc = allocator_type());

2. operator=

cpp 复制代码
//用另一个map对象赋值
map& operator= (const map& x);
//用初始化列表进行赋值
map& operator= (initializer_list<value_type> il);

3. iterator

cpp 复制代码
//返回的是一个指向map容器中第一个元素的迭代器
//如果容器为空,返回的迭代器值不应被解引用
iterator begin() noexcept;
const_iterator begin() const noexcept;
//返回的是一个指向map容器中最后一个元素之后位置的迭代器
iterator end() noexcept;
const_iterator end() const noexcept;
//返回的是一个指向容器中最后一个元素的迭代器
reverse_iterator rbegin() noexcept;
const_reverse_iterator rbegin() const noexcept;
//返回的是一个指向容器中第一个元素前一个位置的迭代器
reverse_iterator rend() noexcept;
const_reverse_iterator rend() const noexcept;

4. capacity

cpp 复制代码
//判空
bool empty() const noexcept;
//返回的是map容器中元素的个数
size_type size() const noexcept;

5. operator[]

cpp 复制代码
//如果在容器中匹配到了和k一样的元素,这个函数返回它的mapped value的引用
//如果没有匹配成功,这个函数会用k插入一个新的元素并且返回它的mapped value的引用
mapped_type& operator[] (const key_type& k);

6. modifiy

cpp 复制代码
//插入一个val
//插入成功,迭代器指向新插入的元素,否则指向已经存在的元素
pair<iterator,bool> insert (const value_type& val);
//在pos位置插入值val,pos位置只是一个参考位置
iterator insert (const_iterator position, const value_type& val);
//插入一段迭代器区间
template <class InputIterator>
void insert (InputIterator first, InputIterator last);
//插入一个初始化列表
void insert (initializer_list<value_type> il);
//删除迭代器指向位置的元素
iterator  erase (const_iterator position);
//删除指定参数k的元素
size_type erase (const key_type& k);
//删除一段迭代器区间
iterator  erase (const_iterator first, const_iterator last);
//交换两个map对象的内容
void swap (map& x);
//删除map容器中所有的元素
void clear() noexcept;
//返回一个map中用来比较对象的拷贝,比较对象的参数类型是key_type,默认情况下是一个less对象
key_compare key_comp() const;
//也是返回一个比较对象,这个对象的参数类型是value_type,但
//是在比较过程中不会考虑mapped_type部分。
value_compare value_comp() const;

7. operations

cpp 复制代码
//如果找到的话,返回一个指向该元素的迭代器,否则返回map::end()
iterator find (const key_type& k);
const_iterator find (const key_type& k) const;
//返回在map容器中和k匹配的元素的个数,因为map中所有的元素都是唯一的,只返回1或者0
size_type count (const key_type& k) const;
//返回在map容器中第一个大于等于k元素的迭代器
iterator lower_bound (const key_type& k);
const_iterator lower_bound (const key_type& k) const;
//返回的是在map容器中第一个大于k元素的迭代器
iterator upper_bound (const key_type& k);
const_iterator upper_bound (const key_type& k) const;
//返回的是在map容器中所有和k相等元素的范围边界
//由于map中所有的元素都是唯一的,所以,这个范围最多只包含一个元素
//如果没有找到,该范围的长度为0,两个迭代器都指向大于k的第一个元素
pair<const_iterator,const_iterator> equal_range (const key_type& k) const;
pair<iterator,iterator> equal_range (const key_type& k);


四、multimap和map的差异

multimap也是一个关联式容器,与map的不同点在于multimap支持数据冗余

multimap和map的使用基本类似主要区别点在于 是否支持关键值key冗余在insert、find、count、erase函数有所差异,这里跟multiset和set是一样的其次multimap不支持[],因为支持key冗余,[]只能支持插入了,不支持修改

相关推荐
我滴老baby1 小时前
0基础速通Python+AI|2026热门轻量化玩法全攻略:从入门到实战,3天搞定AI应用开发
开发语言·人工智能·python
一个天蝎座 白勺 程序猿1 小时前
Python(29)Python生成器函数深度解析:asyncio事件循环的底层实现与异步编程实战
开发语言·python
2zcode1 小时前
原创文档:基于MATLAB的线性预测编码变声器系统
开发语言·matlab·语音识别
七夜zippoe1 小时前
Python RESTful API设计终极指南:从理论到企业级实战
开发语言·python·http·pandas·restful api
Andy1 小时前
C++ list容器基本逻辑结构详解
c++·windows·list
lly2024061 小时前
Highcharts 配置说明
开发语言
车位涂鸦1 小时前
在线浏览“秀人网合集”的新思路:30 行 Python 把封面图链接秒变本地可点图库
开发语言·python
中草药z1 小时前
【测试基础】Python 核心语法,一篇搞定测试脚本开发基础
开发语言·笔记·python·学习·测试·语法
lsx2024061 小时前
XHR 请求:详解与使用
开发语言