解密set与multiset容器的神秘力量
- 引言
- 一、set和 multiset容器概述
- 二、set容器常用API
- 三、multiset的常用API
- 四、对组 pair
- 4.1、概念
- 4.2、创建对组 pair 的方式
- 五、使用示例
- 5.1、重定义排序规则
- 5.2、队组pair的使用
- 总结
引言
💡 作者简介:一个热爱分享高性能服务器后台开发知识的博主,目标是通过理论与代码实践的结合,让世界上看似难以掌握的技术变得易于理解与掌握。技能涵盖了多个领域,包括C/C++、Linux、Nginx、MySQL、Redis、fastdfs、kafka、Docker、TCP/IP、协程、DPDK等。
👉
🎖️ CSDN实力新星、CSDN博客专家
👉
🔔 专栏介绍:从零到c++精通的学习之路。内容包括C++基础编程、中级编程、高级编程;掌握各个知识点。
👉
🔔 专栏地址:C++从零开始到精通
👉
🔔 博客主页:https://blog.csdn.net/Long_xu
🔔 上一篇:【043】解密C++ STL:深入理解并使用 list 容器
一、set和 multiset容器概述
STL(Standard Template Library)中的set
和multiset
是两种常用的关联容器,用于存储一组有序且唯一的元素。它们具有以下基本概念:
-
set
容器:set
是一个有序容器,其中的元素按照特定的排序准则进行排序。- 每个元素在
set
中只能存在一次,重复的插入将无效。 - 使用二叉搜索树(红黑树)数据结构来实现元素的存储和检索,因此其插入、删除和查找操作的平均时间复杂度为O(logN),其中N是元素的数量。
set
中的元素默认以升序排列,也可以自定义排序规则。
-
multiset
容器:multiset
与set
类似,但允许存储重复的元素。- 元素在
multiset
中按照特定的排序准则进行排序,并且插入操作总是成功,不会检测重复元素。 - 与
set
相比,multiset
的插入、删除和查找操作的平均时间复杂度也是O(logN)。
这两种容器都提供了一系列的成员函数和迭代器来操作和访问元素,例如插入元素、删除元素、查找元素等。此外,它们还提供了丰富的算法和操作符重载来方便地处理容器中的元素。
注意:在使用set
和multiset
时,由于元素的有序性和二叉搜索树的特性,插入、删除和查找操作的时间复杂度相对于其他容器(如vector
或list
)可能更高。
二、set容器常用API
下面是set
容器的常用接口函数原型:
- 构造函数:
explicit set(const Compare& comp = Compare(), const Allocator& alloc = Allocator());
explicit set(const Allocator& alloc);
template <class InputIterator>
set(InputIterator first, InputIterator last, const Compare& comp = Compare(), const Allocator& alloc = Allocator());
set(const set& other);
set(set&& other) noexcept;
- 插入和删除元素:
iterator insert(const value_type& value);
iterator insert(value_type&& value);
iterator insert(const_iterator hint, const value_type& value);
iterator insert(const_iterator hint, value_type&& value);
template <class InputIterator>
void insert(InputIterator first, InputIterator last);
void erase(iterator position);
size_type erase(const key_type& key);
void erase(iterator first, iterator last);
void clear() noexcept;
- 访问元素和容量相关:
iterator find(const key_type& key);
const_iterator find(const key_type& key) const;
size_type count(const key_type& key) const;
bool empty() const noexcept;
size_type size() const noexcept;
- 迭代器相关:
iterator begin() noexcept;
const_iterator begin() const noexcept;
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;
const_iterator cbegin() const noexcept;
const_iterator cend() const noexcept;
const_reverse_iterator crbegin() const noexcept;
const_reverse_iterator crend() const noexcept;
这里只列举了部分常用的接口函数原型,set
容器还包含其他许多用于比较、交换、合并等操作的函数。此外,还可以通过迭代器对容器中的元素进行遍历和访问。
例如:下面是set
容器的upper_bound
、lower_bound
和equal_range
接口函数的原型:
upper_bound
函数原型:
iterator upper_bound(const key_type& key);
const_iterator upper_bound(const key_type& key) const;
lower_bound
函数原型:
iterator lower_bound(const key_type& key);
const_iterator lower_bound(const key_type& key) const;
equal_range
函数原型:
std::pair<iterator, iterator> equal_range(const key_type& key);
std::pair<const_iterator, const_iterator> equal_range(const key_type& key) const;
这些函数用于在set
容器中进行元素搜索。它们根据元素的键值进行查找,并返回满足特定条件的迭代器或迭代器范围。
upper_bound
函数返回一个迭代器,指向第一个大于给定键值的元素位置。lower_bound
函数返回一个迭代器,指向第一个不小于给定键值的元素位置。equal_range
函数返回一个包含两个迭代器的pair
对象,分别表示与给定键值匹配的元素范围的起始和结束位置。
注意以上函数假设set
容器中的元素已经按照严格弱排序的方式(默认是由小到大)进行了排序。
三、multiset的常用API
下面是multiset
容器的所有接口函数的原型:
- 构造函数:
explicit multiset(const Compare& comp = Compare(), const Allocator& alloc = Allocator());
explicit multiset(const Allocator& alloc);
template <class InputIterator>
multiset(InputIterator first, InputIterator last, const Compare& comp = Compare(), const Allocator& alloc = Allocator());
multiset(const multiset& other);
multiset(multiset&& other) noexcept;
- 插入和删除元素:
iterator insert(const value_type& value);
iterator insert(value_type&& value);
iterator insert(const_iterator hint, const value_type& value);
iterator insert(const_iterator hint, value_type&& value);
template <class InputIterator>
void insert(InputIterator first, InputIterator last);
void erase(iterator position);
size_type erase(const key_type& key);
void erase(iterator first, iterator last);
void clear() noexcept;
- 访问元素和容量相关:
iterator find(const key_type& key);
const_iterator find(const key_type& key) const;
size_type count(const key_type& key) const;
bool empty() const noexcept;
size_type size() const noexcept;
- 迭代器相关:
iterator begin() noexcept;
const_iterator begin() const noexcept;
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;
const_iterator cbegin() const noexcept;
const_iterator cend() const noexcept;
const_reverse_iterator crbegin() const noexcept;
const_reverse_iterator crend() const noexcept;
lower_bound
、upper_bound
和equal_range
接口函数的原型与set
相同。
这些函数的作用和用法与set
容器类似,但multiset
容器允许存储重复的键值,因此在插入和删除元素时不会执行唯一性检查。其余的特性和接口函数与set
相同。
四、对组 pair
对组(pair)将一对值组合成一个值,这一对值可以具有不同的数据类型,两个值可以分别用pair的两个公有属性first和second模板: template <class T1, class T2> struct pair。
4.1、概念
STL(Standard Template Library)提供了一个名为pair
的模板类,用于表示有序的、具有固定数量的数据元素对。pair
模板类定义在 <utility>
头文件中。
pair
模板类的定义如下:
template<class T1, class T2>
struct pair {
typedef T1 first_type; // 第一个元素类型
typedef T2 second_type; // 第二个元素类型
T1 first; // 第一个元素
T2 second; // 第二个元素
// 构造函数
template<class U, class V>
pair(U&& x, V&& y);
...
};
pair
类具有以下特性和功能:
-
pair
类包含公共的两个成员变量:first
和second
,分别存储第一个元素和第二个元素。 -
可以通过直接访问成员变量
first
和second
来获取或修改元素的值。 -
pair
类支持复制构造函数、移动构造函数和赋值运算符重载。 -
参数化类型
T1
和T2
决定了pair
可以存储的元素类型。可以是任何可复制、可比较和可分配内存的类型。 -
pair
类还提供了方便的构造函数用于创建对象,并将传入的值分配给first
和second
。 -
pair
类还支持比较操作符(如==
、!=
、<
、>
、<=
、>=
)的重载,用于比较两个pair
对象之间的大小关系。
使用示例:
#include <iostream>
#include <utility>
int main() {
std::pair<int, double> myPair(10, 3.14);
std::cout << "First element: " << myPair.first << std::endl;
std::cout << "Second element: " << myPair.second << std::endl;
myPair.first = 20;
myPair.second = 2.71;
std::cout << "Modified first element: " << myPair.first << std::endl;
std::cout << "Modified second element: " << myPair.second << std::endl;
return 0;
}
输出结果:
First element: 10
Second element: 3.14
Modified first element: 20
Modified second element: 2.71
4.2、创建对组 pair 的方式
在STL中,创建pair
对象有多种方式:
- 使用构造函数创建:
#include <utility>
std::pair<int, double> myPair(10, 3.14);
- 使用
make_pair
函数创建:
#include <utility>
auto myPair = std::make_pair(10, 3.14);
- 使用花括号初始化列表创建(C++11及以上版本):
#include <utility>
auto myPair = std::pair<int, double>{10, 3.14};
- 使用赋值运算符创建:
#include <utility>
std::pair<int, double> myPair;
myPair = std::make_pair(10, 3.14);
无论使用哪种方式创建pair
对象,都要指定两个元素的类型,并提供对应数量的参数来初始化first
和second
成员变量。
五、使用示例
5.1、重定义排序规则
仿函数:重载函数调用运算符()的类。
class MyGreater
{
public:
bool operator() (int v1, int v2){
return v1>v2;
}
};
void test(){
// set<int,排序规则>sl;
set<int,MyGreatersl;s1.insert(30);
s1.insert(10);
s1.insert(20);
s1.insert(50);
s1.insert(40);
}
set存放自定义数据必须修改排序
5.2、队组pair的使用
void test()
{
set<int> sl;
s1.insert(10);
s1.insert(30);
s1.insert(50);
s1.insert(70);
s1.insert(90);
set<int> : : const_iterator ret;
ret = s1 .lower_bound (50);
if(ret!=s1.end( ) )
{
cout<<"下限为:"<<*ret<<endl;
}
ret = s1.upper_bound (50);
if(ret! =s1.end())
{
cout<<"上限为:"<<*ret<<endl;
}
//以对组的方式存储上下限pair
pair< set<int> : :const_iterator , set<int> ::const_iterator> pa;
pa= s1.equal_range(50);
if(pa.first != s1.end())
{
cout<<"下限为:"<<*(pa.first)<<endl;
}
if(pa.second != s1.end())
{
cout<<"上限为:"<<*(pa.second)<<endl;
}
总结
- set的特性是所有元素都会根据元素的键值自动被排序,set的元素即是键值又是实值。
- set不允许两个元素有相同的键值。
- set容器的迭代器是只读迭代器,不允许修改键值,会破坏set的内存布局。
- multiset特性及用法和set完全相同,唯一的差别在于它允许键值重复。