Set
set 简介
Set(集合)是一种数据结构,用于存储唯一且已排序的元素。
以下是关于 set 的关键点:
- 唯一性: Set 中不允许存在重复的元素。当尝试插入已存在的元素时,通常不会发生任何改变。
- 已排序: Set 中的元素会根据某种排序准则(例如,使用
<
运算符,或者用户提供的比较函数)进行排序。 - 基于键的存储: 尽管 set 主要存储元素本身,但其内部实现是基于元素的键(即元素自身)进行排序和组织的,这与 map 类似,map 存储的是
<key, element>
对并基于键排序。
实现方式:
- 在标准模板库 (STL) 中,set 通常是使用红黑树(red-black tree)实现的。红黑树是一种自平衡的二叉搜索树,能够保证在最坏情况下,插入和删除等操作的时间复杂度为 O(lg n),其中 n 是 set 中元素的数量。
- 为什么选择红黑树?
- 相对于简单的向量实现,红黑树在插入操作上具有更高的效率。在无序向量中插入需要 O(n) 的时间来检查元素是否已存在。在有序向量中,虽然可以使用二分搜索在 O(lg n) 时间内找到插入位置,但移动后续元素以腾出空间需要 O(n) 的时间。
- 红黑树通过其平衡特性,保证了插入和删除操作的对数时间复杂度,这使得 set 在需要频繁进行这些操作的场景中非常高效.
- 迭代器: set 的迭代器以**中序遍历(inorder traversal)**的方式访问树中的节点,从而保证按排序顺序访问 set 中的元素。
- 常量迭代器: 由于修改 set 中节点的信息可能会破坏其键的排序,因此 set 通常只提供常量迭代器,这意味着不能通过迭代器直接修改 set 中的元素的值。如果需要对 set 中的元素进行修改,通常需要先删除该元素,然后插入修改后的新元素。
常用操作:
Set 提供了一系列成员函数来操作集合,包括但不限于:
insert(const T& el)
: 插入元素el
。如果元素已存在,则不会进行插入(对于 set)。erase(const T& el)
: 删除值为el
的元素。find(const T& el) const
: 查找值为el
的元素,如果找到则返回指向该元素的迭代器,否则返回指向end()
的迭代器。count(const T& el) const
: 返回 set 中值为el
的元素的个数(对于 set,结果要么是 0,要么是 1)。empty() const
: 检查 set 是否为空。size() const
: 返回 set 中元素的个数。clear()
: 移除 set 中的所有元素.begin()
: 返回指向第一个元素的迭代器.end()
: 返回指向 set 尾部(最后一个元素之后)的迭代器.swap(set<T>& s)
: 与另一个 sets
交换内容.
简单来说,Set 是一种用于存储唯一且已排序元素的高效数据结构。它通常基于红黑树实现,提供了快速的插入、删除和查找操作。 您可以将其想象成一个不允许重复的书架,书本按照某种规则(例如书名)有序地排列在上面。
set 成员函数
成员函数 | 描述 |
---|---|
insert(const T& el) |
将元素 el 插入到 set 中。如果元素已存在,则不进行插入。返回一个 pair<iterator, bool> ,其中迭代器指向插入的元素(或已存在的元素),bool 值指示是否成功插入。 |
erase(const T& el) |
从 set 中移除所有等于 el 的元素。返回移除的元素个数。 |
erase(iterator position) |
移除迭代器 position 指向的元素。 |
erase(iterator first, iterator last) |
移除范围 [first, last) 内的所有元素。 |
clear() |
移除 set 中的所有元素。 |
find(const T& el) const |
返回一个指向 set 中第一个等于 el 的元素的迭代器。如果未找到,则返回 end() 。 |
count(const T& el) const |
返回 set 中等于 el 的元素个数(对于 set 来说,结果要么是 0,要么是 1)。 |
empty() const |
如果 set 为空,则返回 true ,否则返回 false 。 |
size() const |
返回 set 中元素的个数。 |
begin() const |
返回指向 set 中第一个元素的迭代器。 |
end() const |
返回指向 set 中最后一个元素之后位置的迭代器。 |
rbegin() const |
返回指向 set 中最后一个元素的逆向迭代器。 |
rend() const |
返回指向 set 中第一个元素之前位置的逆向迭代器。 |
lower_bound(const T& el) const |
返回一个指向 set 中第一个不小于 el 的元素的迭代器。 |
upper_bound(const T& el) const |
返回一个指向 set 中第一个大于 el 的元素的迭代器。 |
equal_range(const T& el) const |
返回一个 pair<iterator, iterator> ,表示 set 中所有等于 el 的元素的范围。 |
swap(set& other) |
将当前 set 的内容与另一个 set other 的内容进行交换。 |
set DEMO 程序
#include <iostream>
#include <set>
#include <iterator>
using namespace std;
int main() {
// 创建一个存储整数的 set
set<int> mySet;
// 插入元素
mySet.insert(3);
mySet.insert(1);
mySet.insert(4);
mySet.insert(1); // 插入重复元素,不会生效
mySet.insert(5);
mySet.insert(9);
cout << "Set 中的元素 (升序): ";
for (int element : mySet) {
cout << element << " ";
}
cout << endl;
// 检查 set 是否为空
if (mySet.empty()) {
cout << "Set 是空的" << endl;
} else {
cout << "Set 不是空的,包含 " << mySet.size() << " 个元素" << endl;
}
// 查找元素
int searchElement = 4;
if (mySet.find(searchElement) != mySet.end()) {
cout << searchElement << " 在 set 中找到" << endl;
} else {
cout << searchElement << " 未在 set 中找到" << endl;
}
// 统计元素个数
int countElement = 1;
cout << countElement << " 在 set 中出现了 " << mySet.count(countElement) << " 次" << endl;
// 删除元素
int eraseElement = 3;
mySet.erase(eraseElement);
cout << "移除 " << eraseElement << " 后的 Set: ";
for (int element : mySet) {
cout << element << " ";
}
cout << endl;
// 使用迭代器删除元素
set<int>::iterator it = mySet.find(5);
if (it != mySet.end()) {
mySet.erase(it);
cout << "移除 5 后的 Set: ";
for (int element : mySet) {
cout << element << " ";
}
cout << endl;
}
// 使用 lower_bound 和 upper_bound
cout << "第一个不小于 4 的元素是: " << *mySet.lower_bound(4) << endl;
cout << "第一个大于 4 的元素是: " << *mySet.upper_bound(4) << endl;
// 清空 set
mySet.clear();
cout << "清空 Set 后的大小: " << mySet.size() << endl;
return 0;
}