1. 简介
set是一种关联式容器,包含的key值唯一,且会进行排序;增加、修改和查询具有对数的时间复杂度,其存储结构为红黑树;
头文件和定义
//头文件
#include <set>
//定义
template<
class Key,
class Compare = std::less<Key>,
class Allocator = std::allocator<Key>
> class set;
2. 初始化
初始化的方法主要包括直接初始化、复制初始化和拷贝初始化
示例
#include <iostream>
#include <set>
#include <string>
#include <algorithm>
template<typename T>
void showInfo(T &t)
{
for(auto &au : t)
{
std::cout<<au<<" ";
}
}
int main(int argc, char *argv[])
{
std::set<std::string> s;
s.emplace("c++");
s.emplace("c");
s.emplace("java");
s.emplace("shell");
//std::for_each(s.begin(), s.end(), [](auto &a){std::cout<<a<<" ";}); //自动类型推导c++14之后才支持
//std::for_each(s.begin(), s.end(), [](std::string str){std::cout<<str<<" ";}); //指定类型,c++11就可以
showInfo(s);
std::cout<<std::endl;
std::set<int32_t> s1;
s1 = {23,4,5,1,2,10};
showInfo(s1);
std::cout<<std::endl;
std::set<int32_t> s2{34,5,6,7,98,1,2};
showInfo(s2);
std::cout<<std::endl;
std::set<int32_t> s3 = s2;
showInfo(s3);
std::cout<<std::endl;
std::set<int32_t> s4 = {100,200,50,160,50,160}; //重复的数据会被过滤掉
showInfo(s4);
std::cout<<std::endl;
return 0;
}
结果
c c++ java shell
1 2 4 5 10 23
1 2 5 6 7 34 98
1 2 5 6 7 34 98
50 100 160 200
3. 使用
3.1 元素访问
方法 | 说明 |
---|---|
iterator | 集合元素的遍历 |
示例
int main(int argc, char *argv[])
{
std::set<std::string> s1{"c++", "c", "java", "shell"};
auto it = s1.begin();
std::cout<<"it is: "<<*it<<std::endl;
std::advance(it, 2); //移动位置
std::cout<<"it is: "<<*it<<std::endl;
return 0;
}
输出
it is: c
it is: java
3.2 元素的大小
方法 | 说明 |
---|---|
empty | 集合判空 |
size | 集合大小 |
max_size | 最大容量 |
clear | 清空set的大小 |
swap | 交换两个set的内容 |
示例
int main(int argc, char *argv[])
{
std::set<std::string> s1{"c++", "c", "java", "shell"};
std::cout<<"size is: "<<s1.size()<<std::endl;
std::cout<<"max_size is: "<<s1.max_size()<<std::endl;
std::cout<<"\n"<<"[s1 s2]"<<std::endl;
std::set<std::string> s2{"student", "teacher"};
showInfo(s1);
std::cout<<std::endl;
showInfo(s2);
std::cout<<std::endl;
std::cout<<"\n"<<"[swap][s1 s2]"<<std::endl;
s1.swap(s2);
showInfo(s1);
std::cout<<std::endl;
showInfo(s2);
std::cout<<std::endl;
s1.clear();
if(s1.empty())
{
std::cout<<"empty"<<std::endl;
}
else{
std::cout<<"not empty"<<std::endl;
}
return 0;
}
结果
size is: 4
max_size is: 288230376151711743
[s1 s2]
c c++ java shell
student teacher
[swap][s1 s2]
student teacher
c c++ java shell
empty
3.3 元素的修改
主要包括元素的赋值、插入和删除等,相关的操作和list还是存在差异
方法 | 说明 |
---|---|
= | 直接赋值 |
get_allocator | 返回内存分配器 |
insert | 插入元素 |
emplace | 插入元素 |
emplace_hint | 插入元素 |
erase | 删除元素 |
erase_if(C++20) | 条件删除,通常和lambda一起使用 |
extract(C++17) | 元素的删除,可以返回该值 |
merge(C++17) | set的合并 |
示例
int main(int argc, char *argv[])
{
//1.元素增加
std::set<std::string> s1{"c++", "c", "java", "shell"};
std::cout<<"s1 is: ";
showInfo(s1);
std::cout<<"(insert)s1 is: ";
s1.insert("python");
showInfo(s1);
std::cout<<"(emplace)s1 is: ";
s1.emplace("linux");
showInfo(s1);
std::cout<<"(emplace_hint)s1 is: ";
s1.emplace_hint(s1.begin(), "matlab"); //需要带位置
showInfo(s1);
std::cout<<std::endl;
//2.元素删除
auto iter = s1.find("c");
std::cout<<"find value is: "<<*iter<<std::endl;
s1.erase(iter); //erase通常和find()一起使用
showInfo(s1);
std::cout<<std::endl;
//3.extract(17) merge(17)
std::cout<<std::endl;
std::set<int32_t> s2{12,34,5,6,7,89};
auto s2_iter = s2.find(7);
auto va = s2.extract(s2_iter); //元素删除,并可以保存其结果
showInfo(s2);
std::set<int32_t> s3{1,3,5,6,7,9};
s2.merge(s3); //元素的合并
showInfo(s2);
return 0;
}
结果
s1 is: c c++ java shell
(insert)s1 is: c c++ java python shell
(emplace)s1 is: c c++ java linux python shell
(emplace_hint)s1 is: c c++ java linux matlab python shell
find value is: c
c++ java linux matlab python shell
5 6 12 34 89
1 3 5 6 7 9 12 34 89
3.4 元素的操作
方法 | 说明 |
---|---|
count | 计算set中元素出现的次数 |
find | 查找元素 |
equal_range | 返回的是一个范围 [lower_bound, upper_bound] |
lower_bound | 返回当前元素的位置,查找不到返回end |
upper_bound | 返回当前元素的下一个位置,查找不到返回end |
key_comp | 比较函数 |
value_comp | 比较函数 |
示例
int main(int argc, char *argv[])
{
//1.元素计算
std::set<std::string> s1{"c++", "c", "java", "shell","c"};
showInfo(s1);
std::cout<<s1.count("c")<<std::endl;
std::cout<<s1.count("c++")<<std::endl;
//2.find
auto re = s1.find("java1");
if(re != s1.end())
{
std::cout<<"the result of find is: "<<*re<<std::endl;
}
else
{
std::cout<<"can not find the value."<<std::endl;
}
std::cout<<std::endl;
//3.equal_range,返回的是一个范围
auto eq_iter = s1.equal_range("java");
std::cout<<"equal_range first elemenet is: "<<*eq_iter.first<<std::endl;
std::cout<<"equal_range second elemenet is: "<<*eq_iter.second<<std::endl<<std::endl;
//4.lower_bound,返回c++
auto lower_iter = s1.lower_bound("c++");
std::cout<<"lower_iter value is: "<<*lower_iter<<std::endl<<std::endl;
//3.upper_bound,返回java
auto upper_iter = s1.upper_bound("c++");
std::cout<<"upper_iter value is: "<<*upper_iter<<std::endl<<std::endl;
//4.key_comp 比较函数
std::set<int32_t> s2{2,3,4,11,23,44};
auto comp_func = s2.key_comp();
for(auto au : s2)
{
//au > 10? au和10的位置互换,则是10>au
if(comp_func(au, 10))
{
std::cout<<"true ";
}
else{
std::cout<<"false ";
}
}
std::cout<<std::endl;
//5.value_comp 比较函数
auto value_func = s2.value_comp();
for(auto au : s2)
{
//au > 10? au和10的位置互换,则是10>au
if(value_func(au, 10))
{
std::cout<<"true ";
}
else{
std::cout<<"false ";
}
}
std::cout<<std::endl;
return 0;
}
结果
c c++ java shell
1
1
can not find the value.
equal_range first elemenet is: java
equal_range second elemenet is: shell
lower_iter value is: c++
upper_iter value is: java
true true true false false false
true true true false false false
3.5 迭代器
迭代器最好结合STL中的算法一起使用;迭代器的返回值最好用auto接收;
set不能通过下标进行访问,只能通过迭代器访问其中的元素,所以迭代器和其辅助函数用的比较多,同时会加上一些算法;
迭代器的类型包括:iterator、const_iterator、reverse_iterator和const_reverse_iterator
方法 | 说明 |
---|---|
begin | 返回set的头元素(迭代器),其值可修改 |
end | 返回set的尾元素(迭代器),其值可修改 |
cbegin | 返回set的头元素(迭代器),其值不可修改,const属性 |
cend | 返回set的尾元素(迭代器),其值不可修改,const属性 |
rbegin | 反序返回set的头元素(迭代器),其值可修改,同end() |
rend | 反序返回set的尾元素(迭代器),其值可修改,同begin() |
crbegin | 反序返回set的头元素(迭代器),其值不可修改,同cend,const属性 |
crend | 反序返回set的头元素(迭代器),其值不可修改,同cbegin,const属性 |
迭代器的辅助函数
辅助函数的使用需要包含头文件
#include <iterator>
方法 | 说明 |
---|---|
advance | 移动迭代器的位置 |
distance | 计算两个迭代器的距离 |
begin | 返回容器第一个元素的迭代器 |
end | 返回容器最后一个元素的迭代器 |
prev | 迭代器向前移动一个元素 |
next | 迭代器向后移动一个元素 |