一、set概述
set是一个关联式容器,set中,元素都是唯一的,并且在往set中添加元素的时候,会根据元素的值进行自动排序。其内部采用的数据结构是红黑树,红黑树是一种非常高效的平衡检索二叉树。读者若有兴趣,可自行查阅相关资料。set的插入和搜索速度是很快的,set中使用的是二分查找,是log的关系。比如有16个元素的set,最多需要查找4次,有10000个元素,最多需要查找14次,就算元素再增加一倍,达到20000个,最多需要查找15次,也只是多了一次查找而已。
1、为什么set插入、删除的效率比较高?
对于set来讲,不需要内存拷贝和内存移动,set中元素是以节点的方式存储的,插入数据的时候只需要做相应的节点变换即可,删除操作也是类似的,与内存拷贝、内存移动没有任何关系。
2、每次insert后,之前保存的iterator是否会失效?
插入元素的时候,并没有涉及到内存拷贝和内存移动,内存没有变,故不会失效。
二、set的使用
set内部元素是有序的,如果存放的是内置数据类型,会按照默认排序。如果存放自定义数据类型则需要自定义排序。当然,内置数据类型也可以使用自定义排序。
1、自定义排序
方式一:重载<
class Student{
public:
std::string name_;
int age_;
Student(std::string name, int age):name_(name),age_(age){}
Student(){}
bool operator < (const Student &s) const {
if(name_ != s.name_){
return name_ < s.name_;
}else{
return age_ < s.age_;
}
}
std::string show(){
return "name:" + name_ + ", age:" + std::to_string(age_);
}
};
int main(int argc, char *argv[]) {
set<Student> s;
s.emplace(Student("Danney", 22));
s.emplace(Student("LiMing", 20));
s.emplace(Student("LiMing", 18));
for(auto it : s){
cout << it.show() << endl;
}
return 0;
}
方式二:重载()
class Student{
public:
std::string name_;
int age_;
Student(std::string name, int age):name_(name),age_(age){}
Student(){}
std::string show(){
return "name:" + name_ + ", age:" + std::to_string(age_);
}
};
class Comp{
public:
bool operator () (const Student &left, const Student &right){
if(left.name_ != right.name_){
return left.name_ < right.name_;
}else{
return left.age_ < right.age_;
}
}
};
int main(int argc, char *argv[]) {
set<Student, Comp> s;
s.emplace(Student("Danney", 22));
s.emplace(Student("LiMing", 20));
s.emplace(Student("LiMing", 18));
for(auto it : s){
cout << it.show() << endl;
}
return 0;
}
方式三:
class Student{
public:
std::string name_;
int age_;
Student(std::string name, int age):name_(name),age_(age){}
Student(){}
std::string show(){
return "name:" + name_ + ", age:" + std::to_string(age_);
}
};
bool comp (const Student &left, const Student &right){
if(left.name_ != right.name_){
return left.name_ < right.name_;
}else{
return left.age_ < right.age_;
}
}
int main(int argc, char *argv[]) {
set<Student, decltype(comp)*> s(comp);
s.emplace(Student("Janney", 23));
s.emplace(Student("Danney", 22));
s.emplace(Student("LiMing", 20));
s.emplace(Student("LiMing", 18));
for(auto it : s){
cout << it.show() << endl;
}
return 0;
}
2、添加元素:三种方式
set<int> sInt;
//元素添加
//1、返回pair对象,second表示是否添加成功
pair<set<int>::iterator, bool > isSu = sInt.insert(5);
if(isSu.second){
cout << "successful!" << endl;
}
//2、在iterator前插入元素 insert(&pos, value),返回新元素的位置
sInt.insert(isSu.first,9);
//3、添加区间,将区间[&first, &last)区间内的元素添加到set中
int array[] = {4, 10, 6};
sInt.insert(array, array+3);
3、删除元素:四种方式
//元素删除
//1、erase(value),返回移除元素的个数
auto num = sInt.erase(6);
cout << "移除元素个数:" << num << endl;
//2、erase(&pos),移除pos上的元素,无返回值
auto iter = sInt.begin();
sInt.erase(iter);
for(auto it : sInt){
cout << it << ", ";
}
//3、erase(&first, &last),移除[&first, &last)区间内的元素
sInt.erase(sInt.begin(), sInt.end());
cout << endl << "after [fir, last) : " << endl;
for(auto it : sInt){
cout << it << ", ";
}
//4、移除所有元素
sInt.clear();
cout << endl << "after clear : " << endl;
for(auto it : sInt){
cout << it << ", ";
}
4、查找
//查找
//1、count(value),返回value的个数
cout << sInt.count(10) << endl;
//2、iterator find(value),返回value的位置,如果找不到,则返回end()
auto res_find_f = sInt.find(10);
if(res_find_f == sInt.end()){
cout << "未找到" << endl;
}else{
cout << "已找到" << endl;
}
auto res_find_s = sInt.find(20);
if(res_find_s == sInt.end()){
cout << "未找到" << endl;
}else{
cout << "已找到" << endl;
}
5、其他
begin():返回set的第一个元素
end():返回set最后一个元素的下一个位置
empty():判断是否为空
max_size():返回set中可能包含的元素个数最大值
size():返回当前元素个数
rbegin():与end()返回值相同
rend():与begin()返回值相同