C++ set/multiset 容器
C++ set/multiset 容器
文章目录
- C++ set/multiset 容器
- 前言
-
- 1. set 基本概念
- 2. set 构造和赋值
- 3. set 大小和交换
- 4. set 插入和删除
- 5. set 查找和统计
- 6. set和multiset区别
- 7. pair 对组创建
- 8. set 容器排序
- 总结
前言
本文包含set基本概念、set构造和赋值、set大小和交换、set插入和删除、set查找和统计、set和multiset区别、pair对组创建、set容量排序。
1. set 基本概念
简介:
所有元素都会在插入时自动被排序
本质:
set/multiset属于关联式容器,底层结构是用二叉树实现
set和multiset区别:
(1)、set不允许容器中有重复的元素
(2)、multiset允许容器中有重复的元素
2. set 构造和赋值
功能描述:
创建set容器以及赋值
构造:
(1)、set<T> st;
默认构造函数
(2)、set(const set &st);
拷贝构造函数
赋值:
set& operator=(const set &st);
重载等号操作符
// set关联式容器构造和赋值#include <iostream> // 包含标准输入输出流头文件
using namespace std; // 使用标准命名空间#include <set> // 使用set栈容器,需包含头文件set// const对此容器只是只读,不可以修改
void Fun_Print(const set<int>& s) { // 使用引用方式&,传入set<int>类型的形参s// const_iterator只读迭代器;iterator普通迭代器for (set<int>::const_iterator it = s.begin(); it != s.end(); it++) {//*it= 100; // 报错,容器中数据不可修改:表达式必须是可修改的左值cout << *it << " "; // it是个迭代器类型,本是是个指针,需使用*解引用}cout << endl;
}void test() {// 1、默认构造,无参构造set<int> s;// 插入数据,只有insert方式s.insert(10);s.insert(40);s.insert(70);// set关联式容器特点:1、所有元素插入时候自动被排序;2、set关联式容器不允许插入重复值Fun_Print(s); // Fun_Print()遍历容器// 2、拷贝构造函数set<int> s1(s);Fun_Print(s1);// 3、赋值,重构operator=set<int> s2;s2 = s;Fun_Print(s2);
}int main() {test();system("pause"); // 相当于在本地 Windows 调试器中的:请按任意键继续...;暂停,方便看清楚输出结果return 0; // 程序正常退出
}
3. set 大小和交换
功能描述:
统计set容器大小以及交换set容器
函数原型:
(1)、empty();
判断容器是否为空
(2)、size();
返回容器中元素的数目
(3)、swap(st);
交换两个集合容器
// set关联式容器大小和交换#include <iostream> // 包含标准输入输出流头文件
using namespace std; // 使用标准命名空间#include <set> // 使用set栈容器,需包含头文件set// const对此容器只是只读,不可以修改
void Fun_Print(const set<int>& s) { // 使用引用方式&,传入set<int>类型的形参s// const_iterator只读迭代器;iterator普通迭代器for (set<int>::const_iterator it = s.begin(); it != s.end(); it++) {//*it= 100; // 报错,容器中数据不可修改:表达式必须是可修改的左值cout << *it << " "; // it是个迭代器类型,本是是个指针,需使用*解引用}cout << endl;
}void test() {// 创建set容器对象,并且通过模板参数指定容器中存放的数据的类型set<int> s;set<int> s1;// 插入数据,只有insert方式s.insert(10);s.insert(40);s.insert(70);s1.insert(300);s1.insert(200);s1.insert(800);Fun_Print(s); // 10 40 70Fun_Print(s1); // 300 200 800// 1、empty()判断容器是否为空,为空返回真if (s.empty()) {cout << "s容器为空!" << endl;}else {cout << "s容器不为空!" << endl;// 2、size()返回容器的个数cout << "s容器的个数为:" << s.size() << endl; // 3}// 3、swap()交换两个容器中的数据元素s1.swap(s);Fun_Print(s); // 300 200 800Fun_Print(s1); // 10 40 70
}int main() {test();system("pause"); // 相当于在本地 Windows 调试器中的:请按任意键继续...;暂停,方便看清楚输出结果return 0; // 程序正常退出
}
4. set 插入和删除
功能描述:
set容器进行插入数据和删除数据
函数原型:
(1)、insert(elem);
在容器中插入元素
(2)、erase(pos);
删除pos迭代器所指的元素,返回下一个元素的迭代器
(3)、erase(elem);
删除容器中值为elem的元素
(4)、erase(beg, end);
删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器
(5)、clear();
清除所有元素
// set关联式容器插入和删除#include <iostream> // 包含标准输入输出流头文件
using namespace std; // 使用标准命名空间#include <set> // 使用set栈容器,需包含头文件set// const对此容器只是只读,不可以修改
void Fun_Print(const set<int>& s) { // 使用引用方式&,传入set<int>类型的形参s// const_iterator只读迭代器;iterator普通迭代器for (set<int>::const_iterator it = s.begin(); it != s.end(); it++) {//*it= 100; // 报错,容器中数据不可修改:表达式必须是可修改的左值cout << *it << " "; // it是个迭代器类型,本是是个指针,需使用*解引用}cout << endl;
}void test() {// 创建set容器对象,并且通过模板参数指定容器中存放的数据的类型set<int> s;// 1、insert()在容器中插入数据;set容器默认排序规则为从小到大s.insert(10);s.insert(40);s.insert(70);s.insert(50);s.insert(80);Fun_Print(s); // 10 40 50 70 80// 2、erase()删除s容器开始迭代器处的数据元素s.erase(s.begin());Fun_Print(s); // 40 50 70 80// 3、erase()删除s容器中值为50的数据元素s.erase(50);Fun_Print(s); // 40 70 80// 4、erase()删除s容器开始迭代器到结束迭代器中的数据元素s.erase(s.begin(), s.end());Fun_Print(s); //// 5、clear()清空容器中所有的数据元素s.clear();Fun_Print(s); //
}int main() {test();system("pause"); // 相当于在本地 Windows 调试器中的:请按任意键继续...;暂停,方便看清楚输出结果return 0; // 程序正常退出
}
5. set 查找和统计
功能描述:
对set容器进行查找数据以及统计数据
函数原型:
(1)、find(key);
查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end()
(2)、count(key);
统计key的元素个数 (0或1)
// set关联式容器查找和统计#include <iostream> // 包含标准输入输出流头文件
using namespace std; // 使用标准命名空间#include <set> // 使用set栈容器,需包含头文件set// const对此容器只是只读,不可以修改
void Fun_Print(const set<int>& s) { // 使用引用方式&,传入set<int>类型的形参s// const_iterator只读迭代器;iterator普通迭代器for (set<int>::const_iterator it = s.begin(); it != s.end(); it++) {//*it= 100; // 报错,容器中数据不可修改:表达式必须是可修改的左值cout << *it << " "; // it是个迭代器类型,本是是个指针,需使用*解引用}cout << endl;
}void test() {// 创建set容器对象,并且通过模板参数指定容器中存放的数据的类型set<int> s;// 在容器中插入数据;set容器默认排序规则为从小到大s.insert(10);s.insert(40);s.insert(70);s.insert(50);s.insert(80);// 1、find()查找s容器是否存在“50”这个数据元素set<int>::iterator pos = s.find(50); // 返回迭代器,使用set<int>::iterator迭代器pos进行接收if (pos == s.end()) {cout << "未找到元素" << endl;}else {cout << "找到了元素 : " << *pos << endl; // 找到了元素 : 50;使用*解出这个迭代器的值}// 2、count()统计s容器中“50”数据元素的个数int num = s.count(50);cout << "num = " << num << endl; // num = 1
}int main() {test();system("pause"); // 相当于在本地 Windows 调试器中的:请按任意键继续...;暂停,方便看清楚输出结果return 0; // 程序正常退出
}
6. set和multiset区别
学习目标:
掌握set和multiset的区别
区别:
(1)、set插入数据的同时会返回插入结果,表示插入是否成功
(2)、set不可以插入重复数据,而multiset可以
(3)、multiset不会检测数据,因此可以插入重复数据
// set关联式容器和multiset关联式容器区别#include <iostream> // 包含标准输入输出流头文件
using namespace std; // 使用标准命名空间#include <set> // 使用set栈容器,需包含头文件setvoid test() {// 创建set容器对象,并且通过模板参数指定容器中存放的数据的类型set<int> s;// 1、set插入数据的同时会返回插入结果,表示插入是否成功;返回pair对组pair<set<int>::iterator, bool> res = s.insert(10); // pair对组,成对出现的一组数据;set<int>::iterator代表插入元素的位置;bool代表插入成功还是失败if (res.second) { // res.second取res的second第二个数据(bool值)cout << "第一次插入成功!" << endl; // 第一次插入成功!}else {cout << "第一次插入失败!" << endl;}// 2、set不可以插入重复数据,插入重复的10res = s.insert(10);if (res.second) {cout << "第二次插入成功!" << endl;}else {cout << "第二次插入失败!" << endl; // 第二次插入失败!}// 创建multiset容器对象,并且通过模板参数指定容器中存放的数据的类型multiset<int> ms;// 3、multiset不会检测数据,因此可以插入重复数据ms.insert(10);ms.insert(10); // 允许插入重复值for (multiset<int>::iterator it = ms.begin(); it != ms.end(); it++) {cout << *it << " "; // 10 10}cout << endl;
}int main() {test();system("pause"); // 相当于在本地 Windows 调试器中的:请按任意键继续...;暂停,方便看清楚输出结果return 0; // 程序正常退出
}
7. pair 对组创建
功能描述:
成对出现的数据,利用对组可以返回两个数据
两种创建方式:
(1)、pair<type, type> p ( value1, value2 );
(2)、pair<type, type> p = make_pair( value1, value2 );
// pair对组创建#include <iostream> // 包含标准输入输出流头文件
using namespace std; // 使用标准命名空间void test() {// 1、pair<type, type> p ( value1, value2 )pair<string, int> p(string("张三"), 18);cout << "姓名: " << p.first << " 年龄: " << p.second << endl;// 2、pair<type, type> p = make_pair( value1, value2 )pair<string, int> p2 = make_pair("李四", 40);cout << "姓名: " << p2.first << " 年龄: " << p2.second << endl;
}int main() {test();system("pause"); // 相当于在本地 Windows 调试器中的:请按任意键继续...;暂停,方便看清楚输出结果return 0; // 程序正常退出
}
8. set 容器排序
学习目标:
set容器默认排序规则为从小到大,掌握如何改变排序规则
主要技术点:
利用仿函数,可以改变排序规则 仿函数:重载了函数调用运算符“()”
示例一 set存放内置数据类型
// set关联式容器排序:内置数据类型#include <iostream> // 包含标准输入输出流头文件
using namespace std; // 使用标准命名空间#include <set> // 使用set栈容器,需包含头文件set// Fun_Compare仿函数,指定排序类型,从小到大
class Fun_Compare
{public:bool operator()(int v1, int v2) const { // 重载(),返回bool,底层还是需要对两个数进行判断对比return v1 > v2;}
};void test() {// 创建set容器对象,并且通过模板参数指定容器中存放的数据的类型set<int> s;// 在容器中插入数据;set容器默认排序规则为从小到大s.insert(10);s.insert(40);s.insert(70);s.insert(50);s.insert(80);// 默认从小到大for (set<int>::iterator it = s.begin(); it != s.end(); it++) {cout << *it << " "; // 10 20 30 40 50}cout << endl;// 指定排序规则:从大到小// Fun_Compare类型,<>模板内都得放数据类型;仿函数Fun_Compare本质上是一个类型;会按照仿函数Fun_Compare的排序规则进行排序set<int, Fun_Compare> s1; // 插入时就按从小到大给排序好了;如要修改排序规则,不能再插入后指定排序规则;而是要在指定容器时,就指定排序规则,插入前指定s1.insert(10);s1.insert(40);s1.insert(70);s1.insert(50);s1.insert(80);// 遍历set关联式容器for (set<int, Fun_Compare>::iterator it = s1.begin(); it != s1.end(); it++) {cout << *it << " ";}cout << endl;
}int main() {test();system("pause"); // 相当于在本地 Windows 调试器中的:请按任意键继续...;暂停,方便看清楚输出结果return 0; // 程序正常退出
}
示例二 set存放自定义数据类型
// set关联式容器排序:自定义数据类型#include <iostream> // 包含标准输入输出流头文件
using namespace std; // 使用标准命名空间#include <set> // 使用set栈容器,需包含头文件set// 创建一个Person类
class Person
{public:Person(string name, int age) // 构造函数,初始值{this->m_Name = name;this->m_Age = age;}string m_Name; // 姓名int m_Age; // 年龄
};// Fun_Compare仿函数,指定排序类型,从小到大
class Fun_Compare
{public://bool operator()(const Person& p1, const Person &p2) const // const限定,不可修改;使用引号&,防止拷贝构造(浅拷贝)bool operator()(const Person& p1, const Person& p2) const // const限定,不可修改;使用引号&,防止拷贝构造(浅拷贝){// 按照年龄进行排序 降序return p1.m_Age > p2.m_Age;}
};void test() {// 创建set容器对象,并且通过模板参数指定容器中存放的数据的类型set<Person, Fun_Compare> s; // 指定排序顺序Person p1("张三", 18);Person p2("李四", 40);Person p3("王五", 55);Person p4("赵六", 66);// 在容器中插入数据s.insert(p1); // 如果未自定义排序规则Fun_Compare,会报错,编译器插入数据时不知道如何进行从小到大排序s.insert(p2);s.insert(p3);s.insert(p4);// 遍历set关联式容器for (set<Person, Fun_Compare>::iterator it = s.begin(); it != s.end(); it++){cout << "姓名: " << it->m_Name << " 年龄: " << it->m_Age << endl;}
}int main() {test();system("pause"); // 相当于在本地 Windows 调试器中的:请按任意键继续...;暂停,方便看清楚输出结果return 0; // 程序正常退出
}
总结
(1)、set 容器插入数据时用insert;
(2)、set 容器插入数据的数据会自动排序;
(3)、set 统计大小 — size;
(4)、set 判断是否为空 — empty;
(5)、set 交换容器 — swap;
(6)、set 插入 — insert;
(7)、set 删除 — erase;
(8)、set 清空 — clear;
(9)、set 查找 — find (返回的是迭代器);
(10)、set 统计 — count (对于set,结果为0或者1);
(11)、如果不允许插入重复数据可以利用set;
(12)、如果需要插入重复数据利用multiset;
(13)、两种方式都可以创建对组,记住一种即可;
(14)、利用仿函数可以指定set容器的排序规则;
(15)、对于自定义数据类型,set必须指定排序规则才可以插入数据。