C++中的set容器详解

C++中的set容器详解

1. set概述

set是C++ STL中的关联容器,它存储唯一元素 并按特定顺序自动排序。set基于红黑树实现,提供高效的查找、插入和删除操作。

2. 基本特性

  • 唯一性:所有元素都是唯一的
  • 自动排序:元素总是按指定排序规则排列
  • 不可修改元素:元素值不能被直接修改
  • 高效操作 :查找、插入、删除的时间复杂度为O(log⁡2n)O(\log_2 n)O(log2n)

3. 头文件与声明

cpp 复制代码
#include <set>
using namespace std;

set<int> s1;                     // 空set,默认升序
set<int, greater<int>> s2;       // 空set,降序排列
set<string> s3 = {"a", "b"};     // 初始化列表

4. 构造函数与初始化

4.1 默认构造

cpp 复制代码
set<int> s;  // 创建空set

4.2 范围构造

cpp 复制代码
int arr[] = {1, 2, 3};
set<int> s(arr, arr+3);  // 用数组范围构造

4.3 拷贝构造

cpp 复制代码
set<int> s2(s1);  // 拷贝构造

5. 容量操作

5.1 size()

cpp 复制代码
cout << s.size();  // 返回元素数量

5.2 empty()

cpp 复制代码
if(s.empty()) {
    cout << "Set is empty";
}

5.3 max_size()

cpp 复制代码
cout << s.max_size();  // 返回set可容纳的最大元素数

6. 修改操作

6.1 insert()

cpp 复制代码
s.insert(10);                  // 插入单个元素
s.insert({1, 2, 3});           // 插入多个元素
s.insert(s.begin(), 5);        // 带提示插入(不一定提高效率)

6.2 emplace()

cpp 复制代码
s.emplace(10);  // 原地构造元素,比insert更高效

6.3 erase()

cpp 复制代码
s.erase(10);                   // 删除值为10的元素
s.erase(s.begin());            // 删除迭代器指向的元素
s.erase(s.begin(), s.end());   // 删除范围元素

6.4 clear()

cpp 复制代码
s.clear();  // 清空所有元素

7. 查找操作

7.1 find()

cpp 复制代码
auto it = s.find(10);  // 查找元素,返回迭代器
if(it != s.end()) {
    cout << "Found: " << *it;
}

7.2 count()

cpp 复制代码
if(s.count(10)) {  // 返回匹配元素的数量(0或1)
    cout << "Element exists";
}

7.3 lower_bound() & upper_bound()

cpp 复制代码
auto lb = s.lower_bound(5);  // 返回第一个不小于5的元素
auto ub = s.upper_bound(10); // 返回第一个大于10的元素

7.4 equal_range()

cpp 复制代码
auto range = s.equal_range(5);  // 返回等于5的元素范围
// range.first是lower_bound, range.second是upper_bound

8. 迭代器

8.1 begin() & end()

cpp 复制代码
for(auto it = s.begin(); it != s.end(); ++it) {
    cout << *it << " ";
}

8.2 rbegin() & rend()

cpp 复制代码
for(auto rit = s.rbegin(); rit != s.rend(); ++rit) {
    cout << *rit << " ";  // 反向遍历
}

9. 完整示例

cpp 复制代码
#include <iostream>
#include <set>
using namespace std;

int main() {
    // 创建并初始化set
    set<int> s = {5, 2, 8, 1, 3};
    
    // 插入元素
    s.insert(4);
    s.emplace(6);
    
    // 查找元素
    if(s.find(3) != s.end()) {
        cout << "3 found in set\n";
    }
    
    // 删除元素
    s.erase(2);
    
    // 遍历set
    cout << "Set elements: ";
    for(int num : s) {
        cout << num << " ";  // 自动排序输出: 1 3 4 5 6 8
    }
    cout << endl;
    
    // 范围查询
    auto low = s.lower_bound(3);
    auto up = s.upper_bound(5);
    cout << "Elements between 3 and 5: ";
    for(auto it = low; it != up; ++it) {
        cout << *it << " ";  // 输出: 3 4 5
    }
    cout << endl;
    
    // 容量信息
    cout << "Size: " << s.size() << endl;
    cout << "Is empty: " << (s.empty() ? "Yes" : "No") << endl;
    
    return 0;
}

10. 自定义排序规则

cpp 复制代码
struct CaseInsensitiveCompare {
    bool operator()(const string& a, const string& b) const {
        return strcasecmp(a.c_str(), b.c_str()) < 0;
    }
};

set<string, CaseInsensitiveCompare> caseInsensitiveSet;

11. 性能提示

  1. 查找操作优先使用find()而非count()
  2. 插入大量数据时,考虑预先排序后再构造set
  3. 需要修改元素值时,应先删除再插入新值
  4. 使用emplace()替代insert()可避免不必要的拷贝
相关推荐
九转成圣2 小时前
Java 性能优化实战:如何将海量扁平数据高效转化为类目字典树?
java·开发语言·json
SmartRadio2 小时前
ESP32-S3 双模式切换实现:兼顾手机_路由器连接与WiFi长距离通信
开发语言·网络·智能手机·esp32·长距离wifi
laowangpython2 小时前
Rust 入门:GitHub 热门内存安全编程语言
开发语言·其他·rust·github
我叫汪枫2 小时前
在后台管理系统中,如何递归和选择保留的思路来过滤菜单
开发语言·javascript·node.js·ecmascript
_.Switch2 小时前
东方财富股票数据JS逆向:secids字段和AES加密实战
开发语言·前端·javascript·网络·爬虫·python·ecmascript
软件技术NINI2 小时前
webkit简介及工作流程
开发语言·前端·javascript·udp·ecmascript·webkit·yarn
Brendan_0012 小时前
JavaScript的Stomp.over
开发语言·javascript·ecmascript
念2342 小时前
f5 shape分析
开发语言·javascript·ecmascript
苍穹之跃2 小时前
某量JS逆向
开发语言·javascript·ecmascript
思茂信息2 小时前
CST软件如何进行参数化扫描?
运维·开发语言·javascript·windows·ecmascript·软件工程·软件需求