C++ 入门16:STL 容器之集合(set)与多重集合(multiset)

往期回顾:

C++ 入门13:异常处理-CSDN博客

C++ 入门14:STL 容器之向量(vector)-CSDN博客

C++ 入门15:STL 容器之列表(list)-CSDN博客


C++ 入门16:STL 容器之集合(set)与多重集合(multiset)

一、前言

在上一篇文章中,我们深入了解了列表(list)容器,一种双向链表,它在插入和删除元素方面表现卓越。今天我们学习另一种强大的 STL 容器:集合(set)和多重集合(multiset)。这两种容器提供了有序数据存储的功能,能够帮助我们在开发中处理各种需要排序和唯一性检查的场景。

二、STL 容器之集合

2.1、什么是集合(set)?

集合(Set)是一种非常特殊且强大的关联容器,它在数据结构和算法设计中占据重要地位。不同于其他容器如列表(List)或数组(Array),集合的主要特点是它存储的元素是唯一的,且这些元素默认按照某种规则进行排序(尽管在某些实现中,如C++的std::unordered_set,元素并不保证有序,但这里我们主要讨论的是有序集合)。这意味着在集合中,每个元素都只能出现一次,自动去除了重复项。

集合的每个元素都与一个键值(Key)相关联,在集合的上下文中,这个键值实际上就等于元素本身的值。这种键值合一的特性使得集合特别适合于需要快速判断某个元素是否存在,或者需要快速去除重复元素的场景。

为了实现这些高效的操作,集合内部通常采用了一种高效的数据结构作为支撑,其中最常见的就是红黑树(Red-Black Tree)。红黑树是一种自平衡的二叉查找树,它通过旋转操作和重新着色来保持树的平衡,从而确保在最坏情况下,树的深度仍然是对数级别的。这种性质使得集合的插入、删除和查找操作的时间复杂度都能保持在O(log n),其中n是集合中元素的数量。

红黑树的特性确保了集合操作的高效性,同时也使得集合在处理大规模数据集时依然能够保持出色的性能。无论是添加新元素时自动去重,还是快速查找某个元素是否存在,集合都能提供直观且高效的解决方案。

此外,集合还支持一些基本的集合操作,如并集(Union)、交集(Intersection)、差集(Difference)和对称差集(Symmetric Difference)等,这些操作使得集合在解决特定问题时更加灵活和强大。

2.2、集合的基本操作

 (1)创建集合

集合的创建非常简单,你只需包含 <set> 头文件,并定义一个集合类型即可。集合默认按照元素的自然排序规则进行排序,也可以自定义排序规则。

#include <iostream>
#include <set>
using namespace std;

int main() {
    set<int> my_set; // 创建一个空的整数集合

    // 或者使用初始化列表创建集合
    set<int> another_set = {5, 3, 1, 4, 2};

    // 创建一个自定义排序规则的集合(例如按相反顺序排序)
    set<int, greater<int>> descending_set = {5, 3, 1, 4, 2};
    return 0;
}

 (2)插入元素

集合中的元素插入通常使用 insert 函数。由于集合不允许重复元素,所以尝试插入重复元素时,insert 操作将不会有任何效果。

#include <iostream>
#include <set>
using namespace std;

int main() {
    set<int> my_set;

    // 插入元素
    my_set.insert(3);
    my_set.insert(1);
    my_set.insert(2);
    my_set.insert(1); // 尝试插入重复元素,但不会生效

    // 输出集合中的元素
    for (const auto& elem : my_set) {
        cout << elem << ' ';
    }
    cout << endl;

    // 插入提示和返回值
    auto result = my_set.insert(4);
    if (result.second) {
        cout << "Element inserted successfully." << endl;
    } else {
        cout << "Element already exists in the set." << endl;
    }
    return 0;
}

insert 函数的返回值是一个 pair 对象,其中包含一个指向新插入元素的迭代器和一个布尔值,指示插入是否成功。如果元素已经被插入,则返回的布尔值为 false

 (3) 访问元素

由于集合中的元素是有序的,你可以使用迭代器或 find, begin, end, rbegin, rend 等成员函数来访问元素。

A、使用迭代器访问元素
// 遍历并输出所有元素
for (auto it = my_set.begin(); it != my_set.end(); ++it) {
    cout << *it << ' ';
}
cout << endl;
B、使用 find 函数访问特定元素
auto it = my_set.find(3);
if (it != my_set.end()) {
    cout << "Found element: " << *it << endl;
} else {
    cout << "Element not found." << endl;
}
C、访问集合的首尾元素

集合没有直接的 frontback 函数来访问首尾元素,但可以通过迭代器实现类似功能:

cout << "First element: " << *my_set.begin() << endl;
cout << "Last element: " << *my_set.rbegin() << endl; // 注意,rbegin 返回逆序集合的开始迭代器

2.3、 其他集合操作

除了上述基本操作外,集合还提供了许多其他实用的操作,如 erase, swap, clear, empty 等,用于删除元素、交换集合内容、清空集合和检查集合是否为空。v

三、STL 容器之多重集合

3.1、什么是多重集合?

多重集合与集合相似,但是它允许存储重复的元素。这意味着在一个多重集合中,相同的键值可以出现多次。这在需要记录重复数据的场景中非常有用。

多重集合的操作与集合基本相同,只是在插入和查找重复元素时有一些细微差别。

3.2、集合与多重集合的高级操作

(1)查找元素

集合和多重集合提供了 findcount 方法来查找元素:

if (my_set.count(5) > 0) {
    // 元素存在
}

(2)范围操作

使用 lower_boundupper_bound 可以找到给定键值范围内的第一个和最后一个元素:

auto lower = my_set.lower_bound(3);
auto upper = my_set.upper_bound(5);

(3)迭代器操作

集合和多重集合的迭代器提供了对元素的访问和遍历能力:

for (const auto& elem : my_set) {
   cout << elem << ' ';
}

3.3、集合与多重集合的比较

集合和多重集合在功能上相似,但主要区别在于重复元素的处理:

集合

不允许重复元素,每个元素都是唯一的。
多重集合允许重复元素,可以存储多个相同键值的元素。

3.4、性能考量

集合和多重集合基于红黑树实现,这使得它们在插入、删除和查找操作上都表现出较高的效率。然而,由于它们维护元素的排序,所以在某些情况下,如需要频繁插入和删除元素时,可能不如其他容器如向量(vector)或列表(list)那样快。


以上就是 C++ 标准模板库中的集合(set)和多重集合(multiset)的基础知识点了。它们为开发者提供了高效的有序数据存储和检索能力。无论是处理需要排序的元素集合,还是需要统计重复数据的场景,集合和多重集合都能胜任。基本上在开发中都会用到的,大家多看看,一定要掌握。

都看到这里了,点个赞再走呗朋友~

加油吧,预祝大家变得更强!

  • 33
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值