一,set和multiset的基础知识
1.set和multiset的基础
- set是一个集合容器,其中所包含的元素是唯一的,集合中的元素按照一定的顺序排列,元素插入过程是按照排序规则插入的。所以不能指定插入元素的位置。
- set的底层数据结构是红黑二叉树,红黑树属于平衡二叉树。在插入操作和删除操作比vector快。
- set不可以直接存取元素,即不能使用像序列式容器中(vector,deque)那样随机存取。
- multiset和set的区别在于set支持元素唯一,而multiset允许插入多个重复的元素。
- 不可以直接修改set和multiset容器中的元素值,因为该类容器是自动排序的,如果想要修改某个元素的值,需要先删除该元素,然后再重新插入新的元素。
- 要使用set或者multiset要引入的头文件是# include<set>。
2.函数对象的基础知识
set集合默认是从小到大的顺序排序的,如果我们存储的是学生类,想要自定义排序,那么STL提供了函数对象这个概念,所谓的函数对象就是重载了结构体的()操作符。然后返回结果是bool类型。
二,set和multiset的代码示例
1.set和multiset的基本比较
# include<iostream> # include<set> # include<string> using namespace std; int main01() { // 定义set集合 set<string> s1; // 定义multiset集合 multiset<string> s2; // 往set集合中插入元素,其返回结果是一个pair,包含插入进去后的迭代器以及是否插入成功的标志 pair<set<string>::iterator, bool> p1 = s1.insert("Hello"); cout << *p1.first << "," << p1.second << endl; // 我们发现往set集合中插入相同的元素会插入不成功 pair<set<string>::iterator, bool> p2 = s1.insert("Hello"); cout << *p2.first << "," << p2.second << endl; // 遍历 for (string tmp : s1) { cout << tmp << endl; } // 我们往multiset集合中插入元素 s2.insert("Hello"); s2.insert("Hello"); for (string tmp : s2) { cout << tmp << endl; } return 0; }
2.set集合的遍历
# include<iostream> # include<string> # include<set> using namespace std; int main02() { // 定义集合 set<string> s; // 插入集合 s.insert("Hello"); s.insert("world"); s.insert("C++"); // 增强for遍历 for (string tmp : s) { cout << tmp << " "; } cout << endl; // 迭代器正向遍历 for (set<string>::iterator it = s.begin(); it != s.end(); it++) { cout << *it << " "; } cout << endl; // 迭代器逆向遍历 for (set<string>::reverse_iterator it = s.rbegin(); it != s.rend(); it++) { cout << *it << " "; } cout << endl; return 0; }
3.set集合的删除
# include<iostream> # include<set> # include<string> using namespace std; int main03() { // 创建集合 set<string> s; // 插入元素 s.insert("Hello"); s.insert("World"); s.insert("Unreal"); s.insert("C++"); // 删除元素World for (set<string>::iterator it = s.begin(); it != s.end();) { if (*it == "World") { it = s.erase(it); } else { it++; } } // 输出集合的长度 int size1 = s.size(); cout << "size1 = " << size1 << endl; // 遍历元素删除 set<string>::iterator it = s.begin(); while (!s.empty()) { cout << *it << endl; it = s.erase(it); } // 输出集合的长度 int size2 = s.size(); cout << "size = " << size2 << endl; return 0; }
4.set常用的函数
# include<iostream> # include<set> # include<string> using namespace std; int main04() { // set集合默认是从小到大排序的 set<int> s; // 插入元素 s.insert(3); s.insert(2); s.insert(0); s.insert(1); // 遍历元素 for (int tmp : s) { cout << tmp << " "; } cout << endl; // 统计元素出现的次数 int cs = s.count(0); cout << "cs = " << cs << endl; // 查找元素为2的迭代器 set<int>::iterator it = s.find(2); cout << *it << endl; return 0; }
5.自定义函数对象实现对学生类的排序
# include<iostream> # include<string> # include<set> using namespace std; /* 定义学生类,按照其年龄进行排序 */ class Student { public: string name; int age; public: Student(string name, int age) { this->name = name; this->age = age; } }; /* 定义函数对象:所谓的函数对象,就是重载了()操作符的结构体 */ struct StudentFunctor { bool operator()(const Student& stu1,const Student& stu2) { // 如果是>则是从大到小排序,如果是<则是从小到大排序 return stu1.age > stu2.age; } }; int main() { // 定义学生集合 set<Student,StudentFunctor> s; // 插入学生 s.insert(Student("张飞",34)); s.insert(Student("关羽", 45)); s.insert(Student("赵云", 30)); s.insert(Student("马超", 21)); // 打印学生 for (Student stu : s) { cout << stu.name << " = " << stu.age << endl; } return 0; }