> 文章列表 > C++ set/multiset 容器

C++ set/multiset 容器

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必须指定排序规则才可以插入数据。