信奥竞赛

系列

剑指信奥 | C++ 之 STL - set

剑指信奥 | C++ 之 STL - set

特殊的集合

集合 在日常生活中并不陌生的一个词。

比如放学了,排队需要集合,一个班的同学们都聚集在了一起,就是一个集合。

如果一个班里有两个同名的同学,他们也都属于这个集合,因为虽然名字相同,在班级的集合里他们也是两个不同的个体。

今天我们要学习的 STL set 模版类也常常被称为集合,但是,这个集合与上述的集合却有一些不同,我们从一段代码看看这个差异:

#include <iostream>
#include <set>

using namespace std;

int main() {

// set 的初始化
set<string> ss = {"Tom", "Jerry"};

// size 1
cout << "size 1: " << ss.size() << endl;

// 循环输出
for (const auto &item : ss) {
cout << item << endl;
}

// 插入一个元素
ss.insert("Tom");

// size 2
cout << "size 2: " << ss.size() << endl;

// 循环输出
for (const auto &item : ss) {
cout << item << endl;
}

return 0;
}


/*
output:
size 1: 2
Jerry
Tom
size 2: 2
Jerry
Tom
*/

在这段代码中,我们先是初始化了一个集合 ss,内含两个人名 Tom 和 Jerry,然后我们输出了 size,并循环输出了集合中的元素。

之后,我们使用 insert() 函数添加了一个元素 Tom,我们使用这种方式模拟一个班级中的俩个同名的学生,之后再次输出 size,并再次循环输出集合中的元素。

仔细观察运行结果,你都发现了什么?

set 的确是个特殊的集合,我们发现,第二次输出的元素中,还是只有一个 Tom,set不能有重复的元素,这是 set 的第一个特殊之处。

它还有第二个特殊之处,就是放入集合的元素在输出时就完成了排序:Tom 和 Jerry 调换了位置,因为 字母 J 的值小于字母 T 的值,输出时按照默认的升序进行了输出。

set 的有序性基于它底层特殊的数据结构 红黑树 Red-Black Tree。STL 中,集合相关的容器还有很多,set 是最为基本的一个。

下面我们来看下 set 的常用操作。

set 的操作

set 添加元素的主要方法就是 insert(),我们来看下访问元素的方法,请看示例代码:

#include <iostream>
#include <set>

using namespace std;

int main() {

set<int> si = {-3, 1, -4, 1, -5, 9, -2, 6};

cout << "size: " << si.size() << endl;

for (const auto &item : si) {
cout << item << "\t";
}

// 查找 1 是否在集合中
if (si.find(1) != si.end()) {
cout << endl << "find 1 in the set." << endl;
} else {
cout << endl << "not find 1 in the set." << endl;
}

// 统计元素的个数
cout << si.count(9) << endl;
cout << si.count(7) << endl;

return 0;
}


/*
output:
size: 7
-5 -4 -3 -2 1 6 9
find 1 in the set.
1
0
*/

我们在这里使用 find() 函数来查找元素是否在集合中,如果不存在,此函数返回迭代器 end()

我们使用 count() 来统计某个元素在集合中的个数,因为 set 中的每个元素都是唯一的,所以 count() 输出的结果不是 1 就是 0。

最后,我们来看下 set 中删除元素的方法:

#include <iostream>
#include <set>

using namespace std;

int main() {

set<int> si = {-3, 1, -4, 1, -5, 9, -2, 6};

for (const auto &item : si) {
cout << item << "\t";
}

// 删除元素 9
si.erase(9);

cout << endl;

for (const auto &item : si) {
cout << item << "\t";
}

// 清空所有元素
si.clear();

if (si.empty()) { // 判断集合是否为空
cout << endl << "set is empty." << endl;
}

return 0;
}


/*
output:
-5 -4 -3 -2 1 6 9
-5 -4 -3 -2 1 6
set is empty.0
*/

在这里,我们使用函数 erase() 删除集合中的某一个元素,使用 clear() 函数清空集合的所欲元素,最后使用 empty() 函数判断集合是否为空。

STL 的 set 模版类在实际使用中,并不是一个很常用的容器,但是它的元素不能重复的突出特性使得 set 在特定的场景下有着快速去重的作用,也在集合运算中起着重要的作用。