C++语言之set用法

下面简单总结下set容器的操作:

1、set对象的定义和初始化
set对象的定义和初始化方法包括:

set<T> s;
set<T> s(s1);
set<T> s(b, e);
其中,b和e分别为迭代器的开始和结束的标记。

例如:

#include <stdio.h>
#include <vector>
#include <set>

using namespace std;

int main(){
        vector<int> v;
        for (int i = 0; i < 10; i++){
                v.push_back(i);
                v.push_back(i);
        }

        set<int> s(v.begin(), v.end());
        printf("%d\n", v.size());
        printf("%d\n", s.size());
        return 0;
}


注意:键是不能重复的。

2、set中数据的插入
与map不同,set中数据只能通过insert()函数进行插入。

例如:

#include <stdio.h>
#include <vector>
#include <set>

using namespace std;

int main(){
        vector<int> v;
        for (int i = 0; i < 10; i++){
                v.push_back(i);
                v.push_back(i);
        }

        set<int> s;
        s.insert(v.begin(), v.end());
        set<int>::iterator it;
        for (it = s.begin(); it != s.end(); it++){
                printf("%d\t", *it);
        }
        printf("\n");

        s.insert(10);
        for (it = s.begin(); it != s.end(); it++){
                printf("%d\t", *it);
        }
        printf("\n");

        return 0;
}


3、从set中查找和读取元素
从set中查找同样可以使用count()函数和find()函数,两者的区别在之前的map中已经总结。

例如:

#include <stdio.h>
#include <vector>
#include <set>

using namespace std;

int main(){
        vector<int> v;
        for (int i = 0; i < 10; i++){
                v.push_back(i);
                v.push_back(i);
        }

        set<int> s;
        s.insert(v.begin(), v.end());
        set<int>::iterator it;
        for (it = s.begin(); it != s.end(); it++){
                printf("%d\t", *it);
        }
        printf("\n");

        printf("%d\n", s.count(9));
        printf("%d\n", *(s.find(9)));
        return 0;
}


4、从set中删除元素
从set中删除元素使用到的函数是erase()函数,主要有以下的几种形式:

erase(k);
erase(p);
erase(b, e);
其中,p表示的迭代器指向的元素,b和e分别是迭代器的开始和结束。

例如:

#include <stdio.h>
#include <vector>
#include <set>

using namespace std;

int main(){
        vector<int> v;
        for (int i = 0; i < 10; i++){
                v.push_back(i);
                v.push_back(i);
        }

        set<int> s(v.begin(), v.end());
        set<int>::iterator it;
        for (it = s.begin(); it != s.end(); it++){
                if (*it == 5){
                        break;
                }
        }
        s.erase(it, s.end());

        set<int>::iterator it_1;
        for (it_1 = s.begin(); it_1 != s.end(); it_1++){
                printf("%d\t", *it_1);
        }
        printf("\n");

        return 0;
}

 

<think>好的,用户让我详细介绍C++set用法。首先,我需要回想一下用户之前的问题历史。他们之前问过resize()和reserve()的区别,现在转向了STL中的set,可能是在学习容器相关的知识。用户可能对STL的各个容器还不熟悉,需要基础到进阶的内容。 用户的需求是详细了解set用法,包括基本操作、特性、常用方法以及使用场景。他们可能希望了解如何声明和初始化set,如何插入、删除元素,如何查找元素,以及迭代器的使用等。此外,可能还需要知道set的内部实现,比如基于红黑树,这样有助于理解其性能特点。 接下来,我需要考虑如何组织内容。先介绍set的基本概念,强调其有序性和唯一性。然后对比其他类似容器,比如multiset和unordered_set,帮助用户区分不同容器的适用场景。接着分步骤讲解常用操作,包括初始化、插入、删除、查找、遍历等,并给出代码示例,这样用户可以直接看到用法。 还需要注意用户可能的误区,比如为什么不能直接修改set中的元素,或者插入重复元素时的处理。此外,性能分析也很重要,比如查找操作的时间复杂度是O(log n),这样用户在设计算法时可以合理选择数据结构。 用户可能还想知道set的高级用法,比如自定义排序规则,或者结合算法使用。这部分需要提供示例,比如使用lambda表达式定义比较函数,或者使用set_union等算法处理多个集合。 最后,总结部分要强调set的适用场景,比如需要有序且唯一元素的情况,或者频繁查找的情况,帮助用户在实际编程中做出正确选择。同时,指出可能的注意事项,比如元素不可变性、内存占用等,避免用户在使用时遇到问题。 需要确保内容结构清晰,语言通俗易懂,避免过于专业的术语,但又要准确。代码示例要简洁明了,注释详细,方便用户理解。同时,检查是否有遗漏的重要方法,比如emplace、lower_bound等,确保覆盖全面。</think>以下是对C++标准库中`std::set`容器的详细解析: --- ### 一、基本特性 ```cpp #include <set> template < class Key, // 元素类型 class Compare = std::less<Key>, // 排序规则 class Allocator = std::allocator<Key> // 内存分配器 > class set; ``` - **有序容器**:元素按升序自动排序(默认) - **唯一性**:所有元素具有唯一值(不允许重复) - **底层实现**:通常基于红黑树(Red-Black Tree) - **时间复杂度**: - 插入/删除:$O(\log n)$ - 查找:$O(\log n)$ --- ### 二、核心操作详解 #### 1. 初始化 ```cpp // 空集合 set<int> s1; // 初始化列表 set<string> s2 = {"apple", "banana", "cherry"}; // 迭代器范围初始化 vector<int> vec = {5, 2, 2, 8, 3}; set<int> s3(vec.begin(), vec.end()); // {2, 3, 5, 8} // 自定义排序规则(降序) set<int, greater<int>> s4; // 元素从大到小排列 ``` #### 2. 插入元素 ```cpp set<int> s; // insert() 方法 auto ret1 = s.insert(10); // 插入成功,ret1.second为true auto ret2 = s.insert(10); // 插入失败,ret2.second为false // emplace() 高效插入(避免拷贝) s.emplace(20); // 直接构造元素 // 插入多个元素 s.insert({5, 15, 25}); // 插入三个新元素 ``` #### 3. 删除元素 ```cpp set<int> s = {10, 20, 30, 40, 50}; // 通过值删除(返回删除数量) size_t count = s.erase(20); // count=1 // 通过迭代器删除 auto it = s.find(30); if (it != s.end()) s.erase(it); // 删除范围 s.erase(s.begin(), s.find(40)); // 删除40之前的元素 ``` #### 4. 查找与判断 ```cpp set<string> fruits = {"apple", "mango", "pear"}; // find() 查找 auto pos = fruits.find("mango"); if (pos != fruits.end()) { cout << "Found: " << *pos << endl; } // count() 判断存在性 if (fruits.count("grape") == 0) { cout << "Grape not found" << endl; } // contains() (C++20) if (fruits.contains("apple")) { cout << "Apple exists" << endl; } ``` #### 5. 遍历元素 ```cpp set<double> temps = {36.5, 37.0, 38.2}; // 常规迭代器 for (auto it = temps.begin(); it != temps.end(); ++it) { cout << *it << "°C" << endl; } // 反向迭代器 for (auto rit = temps.rbegin(); rit != temps.rend(); ++rit) { cout << *rit << " "; } // 范围for循环 for (const auto& t : temps) { cout << t << " "; } ``` --- ### 三、进阶用法 #### 1. 自定义排序规则 ```cpp // 按字符串长度排序 struct LengthCompare { bool operator()(const string& a, const string& b) const { return a.length() < b.length(); } }; set<string, LengthCompare> words; // {"a", "cat", "apple"} ``` #### 2. 范围查询 ```cpp set<int> nums = {10, 20, 30, 40, 50}; // lower_bound >= 值的第一个元素 auto low = nums.lower_bound(25); // 指向30 // upper_bound > 值的第一个元素 auto up = nums.upper_bound(40); // 指向50 // 区间遍历 [25,45) for (auto it = low; it != up; ++it) { cout << *it << " "; // 输出30 40 } ``` #### 3. 集合运算 ```cpp set<int> a = {1, 2, 3}, b = {2, 3, 4}, result; // 并集 set_union(a.begin(), a.end(), b.begin(), b.end(), inserter(result, result.begin())); // {1,2,3,4} // 交集 set_intersection(...); // 差集 set_difference(...); ``` --- ### 四、性能对比 | **操作** | `std::set` | `std::unordered_set` | `std::vector` | |----------------|------------|----------------------|---------------| | 插入元素 | $O(\log n)$| 平均$O(1)$ | $O(1)$ | | 删除元素 | $O(\log n)$| 平均$O(1)$ | $O(n)$ | | 查找元素 | $O(\log n)$| 平均$O(1)$ | $O(n)$ | | 有序遍历 | 原生支持 | 需要额外排序 | 需要排序 | | 内存占用 | 较高 | 中等 | 低 | --- ### 五、典型应用场景 1. **去重排序** ```cpp vector<int> data = {5, 2, 5, 1, 3}; set<int> unique_sorted(data.begin(), data.end()); // {1,2,3,5} ``` 2. **字典管理** ```cpp set<string> dictionary; while (cin >> word) { dictionary.insert(lowercase(word)); } ``` 3. **范围查询系统** ```cpp set<Time> schedule; // 按时间排序的日程表 auto next = schedule.lower_bound(current_time); ``` 4. **游戏高分榜** ```cpp set<Score, greater<Score>> leaderboard; // 自动维护降序 ``` --- ### 六、注意事项 1. **元素不可变性** ```cpp set<Person> people; auto it = people.find(someone); // *it = modified_person; // 错误!会破坏排序 ``` 2. **自定义类型的比较** ```cpp struct Point { int x, y; bool operator<(const Point& p) const { return x < p.x || (x == p.x && y < p.y); } }; set<Point> points; // 必须定义operator< ``` 3. **性能优化** ```cpp // 批量插入优化 vector<int> bulk_data = {...}; s.insert(bulk_data.begin(), bulk_data.end()); // 比单次插入快 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值