好的!既然你提到了 C++ 标准库中的容器类 <set>
,我将为你详细讲解它的用法,包括基本概念、特性、功能以及实用示例。<set>
是 C++ STL 中的一种关联容器,基于平衡二叉搜索树(通常是红黑树)实现,元素按升序自动排序且唯一。以下是完整的内容,适合学习和实践。
C++ 标准库:<set>
<set>
是一个模板类,表示有序集合。它的主要特点是:
- 自动排序:元素按升序存储,默认使用
<
比较。 - 唯一性:不允许重复元素。
- 高效查找:基于平衡二叉树,查找、插入、删除的时间复杂度为 O(log n)。
- 动态大小:大小随元素增减动态调整。
包含头文件
#include <set>
#include <iostream> // 通常配合使用
定义格式
std::set<类型, 比较器> 变量名;
类型
:集合中元素的数据类型(如int
、double
、std::string
)。比较器
:可选,默认是std::less<T>
(升序),可改为std::greater<T>
(降序)。
基本用法
1. 声明和初始化
#include <set>
#include <iostream>
int main() {
std::set<int> s; // 空集合
std::set<int> s2 = {1, 2, 3, 4, 2}; // 初始化列表(C++11 起),重复的 2 被忽略
std::cout << "s2: ";
for (int val : s2) {
std::cout << val << " "; // 输出:1 2 3 4
}
std::cout << std::endl;
return 0;
}
- 重复元素自动被忽略。
2. 插入元素
#include <set>
#include <iostream>
int main() {
std::set<int> s;
s.insert(10); // 插入
s.insert(30);
s.insert(20);
s.insert(10); // 重复插入无效
std::cout << "s: ";
for (int val : s) {
std::cout << val << " "; // 输出:10 20 30
}
std::cout << std::endl;
return 0;
}
insert()
:O(log n),返回std::pair<iterator, bool>
(迭代器和是否插入成功)。
3. 删除元素
#include <set>
#include <iostream>
int main() {
std::set<int> s = {1, 2, 3, 4};
s.erase(2); // 删除值为 2 的元素
std::cout << "After erase: ";
for (int val : s) {
std::cout << val << " "; // 输出:1 3 4
}
std::cout << std::endl;
return 0;
}
erase()
:O(log n),可按值或迭代器删除。
4. 查找元素
#include <set>
#include <iostream>
int main() {
std::set<int> s = {10, 20, 30};
auto it = s.find(20); // 查找值为 20 的元素
if (it != s.end()) {
std::cout << "Found: " << *it << std::endl; // 输出:Found: 20
} else {
std::cout << "Not found" << std::endl;
}
if (s.count(10)) { // 检查元素是否存在
std::cout << "10 exists" << std::endl; // 输出:10 exists
}
return 0;
}
find()
:O(log n),返回迭代器,找不到返回end()
。count()
:O(log n),返回元素个数(0 或 1,因<set>
无重复)。
5. 大小和状态
#include <set>
#include <iostream>
int main() {
std::set<int> s = {1, 2, 3};
std::cout << "Size: " << s.size() << std::endl; // 输出:3
std::cout << "Empty? " << (s.empty() ? "Yes" : "No") << std::endl; // 输出:No
return 0;
}
size()
:O(1)。empty()
:O(1)。
6. 自定义比较器(降序)
#include <set>
#include <iostream>
int main() {
std::set<int, std::greater<int>> s; // 降序集合
s.insert(10);
s.insert(30);
s.insert(20);
std::cout << "s: ";
for (int val : s) {
std::cout << val << " "; // 输出:30 20 10
}
std::cout << std::endl;
return 0;
}
7. 迭代器
#include <set>
#include <iostream>
int main() {
std::set<std::string> s = {"Apple", "Banana", "Cherry"};
std::cout << "Forward: ";
for (auto it = s.begin(); it != s.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl; // 输出:Apple Banana Cherry
std::cout << "Reverse: ";
for (auto it = s.rbegin(); it != s.rend(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl; // 输出:Cherry Banana Apple
return 0;
}
- 支持双向迭代器:
begin()
/end()
,rbegin()
/rend()
。
与其他容器的对比
特性 | std::set | std::vector | std::list |
---|---|---|---|
数据结构 | 平衡二叉树 | 动态数组 | 双向链表 |
元素顺序 | 自动排序 | 插入顺序 | 插入顺序 |
重复元素 | 不允许 | 允许 | 允许 |
查找 | O(log n) | O(n) | O(n) |
插入/删除 | O(log n) | O(n) | O(1) |
随机访问 | 不支持 | O(1) | 不支持 |
注意事项
- 唯一性:重复插入无效,需用
<multiset>
支持重复元素。 - 迭代器失效:插入不影响现有迭代器,删除使指向被删元素的迭代器失效。
- 性能:查找和插入高效,但不支持随机访问。
- 内存:红黑树结构有额外指针开销。
实用示例:统计唯一单词
#include <set>
#include <iostream>
#include <string>
int main() {
std::set<std::string> words;
std::string input;
std::cout << "Enter words (Ctrl+D or Ctrl+Z to stop):\n";
while (std::cin >> input) {
words.insert(input);
}
std::cout << "Unique words:\n";
for (const std::string& word : words) {
std::cout << word << "\n";
}
std::cout << "Total unique words: " << words.size() << std::endl;
return 0;
}
输入示例:
apple banana apple cherry banana
Ctrl+D
输出:
Unique words:
apple
banana
cherry
Total unique words: 3
小练习
以下是一个基于 <set>
的练习题,你可以尝试:
问题:
写一个 C++ 程序:
- 定义一个
std::set<int>
。 - 插入 10、20、30、20、40(注意重复)。
- 删除值为 20 的元素。
- 输出所有元素和大小。
参考答案(你可以先尝试)
#include <set>
#include <iostream>
int main() {
std::set<int> s;
// 插入元素
s.insert(10);
s.insert(20);
s.insert(30);
s.insert(20); // 重复无效
s.insert(40);
// 删除 20
s.erase(20);
// 输出所有元素和大小
std::cout << "Elements: ";
for (int val : s) {
std::cout << val << " ";
}
std::cout << "\nSize: " << s.size() << std::endl;
return 0;
}
输出:
Elements: 10 30 40
Size: 3
下一步
- 如果你想试试这个练习,请写下你的代码,我会帮你检查。
- 如果你想要更复杂的内容(如自定义比较器、与
<multiset>
对比),或者设计<set>
的测验题,请告诉我! - 你也可以提出具体问题,如“如何用
<set>
实现交集?”或“<set>
和<unordered_set>
的区别?”。
现在,你想做什么?试试练习,还是有其他需求?
发表回复