从C向C++16——常见容器2

一.stack容器

1.stack理解

概念: stack是一种先进后出的数据结构,它只有一个出口。

它在C++中也叫栈,类似于我们在《数据结构和算法》里面的栈,只不过在C++中把其封装成库,我们可以直接使用。

在这里插入图片描述

注意:栈中只有顶端的元素才可以被外界使用,因此栈不允许有遍历行为。

2.stack常用接口

构造函数:

stack<T> stk;                               //stack采用模板类实现,stack对象的默认构造
stack(const stack &stk);                    //拷贝构造函数

赋值操作:

stack& operator=(const stack &stk);             //重载=,类似于拷贝构造

数据存取:

push(elem);                                 //向栈顶添加元素
pop();                                      //从栈顶移除一个元素
top();                                      //返回栈顶元素

大小操作:

empty();                                                  //判断堆栈是否为空
size();                                                   //返回栈的大小

二.queue容器

1.queue理解

概念: Queue是一种先进先出的数据结构,它有两个端口,一个用来进入数据,一个用来拿出数据。

它在C++中也叫队列,类似于我们在《数据结构和算法》里面的队列,只不过在C++中把其封装成库,我们可以直接使用。

在这里插入图片描述

  • 队列容器允许从一端新增元素,从另一端移除元素。
  • 队列中只有队头和队尾才可以被外界使用,因此队列不允许有遍历行为

2.queue常用接口

构造函数:

queue<T> que;                             //queue采用模板类实现,默认构造形式
que(const queue &que);                    //拷贝构造函数

赋值操作:

queue& operator=(const queue &que);                 //重载等号操作符

数据存取:

push(elem);                           //往队尾添加元素
pop();                                //从对头移除第一个元素
back();                               //返回最后一个元素
front();                              //返回第一个元素

大小操作:

empty();                     //判断队列是否为空
size();                      //返回栈的大小

三.list容器

1.list理解

功能:将数据进行链式存储

链表(list)是一种物理存储单元上非连续的存储结构,数据元素的逻辑顺序是通过链表中的指针链接实现的

链表的组成:链表由一系列结点组成

结点的组成:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。

在《数据结构与算法》中,我们说的链表一般是单向不循环链表,而STL中的链表是双向循环链表

在这里插入图片描述

由于链表的存储方式并不是连续的内存空间,因此链表list中的迭代器只支持前移和后移,属于双向迭代器

list的优点:

  • 采用动态存储分配,不会造成内存浪费和溢出
  • 链表执行插入和删除操作十分方便,修改指针即可,不需要移动大量元素

list的缺点:

  • 链表灵活,但是空间(指针域)和 时间 (遍历)额外耗费较大
  • list有一个重要的性质,插入操作和删除操作都不会造成原有list迭代器的失效,这在vector是不成立的.

总结: STL中list和vector是两个最常被使用的容器,各有优缺点。

所以无论如何,务必掌握好这两个容器。

2.list构造函数

list<T> lst;                          //list采用模板类实现,默认构造
list(beg,end);                        //区间拷贝,将[beg,end)区间中的元素拷贝给当前对象
list(n,elem);                         //构造函数将n个elem拷贝给本身
list(const list &lst);                //拷贝构造

list容器与其他的STL容器构造方式几乎没什么区别。

3.list赋值和交换

assign(beg,end);                               //将[beg,end)区间的数据拷贝赋值给当前对象
assign(n,elem);                                //将n个elem拷贝赋值给本身
list& operator=(const list &lst);              //重载=,拷贝赋值
swap(lst);                                     //将lst与当前对象的元素交换

其实一般在构造时就完成了赋值操作,而这里的赋值更多的是采用默认构造后追加赋值。

注意:

  • vectorlist中的swap()都是类模板的成员函数,而不需要算法库
  • vector中的swap()常用来收缩空间

4.list大小操作

size();                            //返回容器中元素的个数
empty();                           //判断容器是否为空
resize(num);                       //重新指定容器的长度为num,若容器变成,则以默认值填充新位置//若容器变短,则末尾超出容器长度被删除
resize(num,elem);                  //重新指定容器的长度为num,若容器变成,则以elem填充新位置//如果容器变短,则末尾超出容器长度的元素被删除

5.list插入和删除

push_back(elem);              //在容器尾部添加一个数据
push_front(elem);             //在容器头部插入一个数据
pop_back();                   //删除容器的最后一个数据
pop_front();                  //删除容器的第一个数据
insert(pos,elem);              //在pos位置插入一个elem元素的拷贝,返回新数据的位置
insert(pos,n,elem);            //在pos位置下插入n个elem数据,无返回值
insert(pos,beg,end);           //在pos位置插入[beg,end)区间的数据,无返回值
clear();                       //情况容器的所有数据
erase(beg,end);                //删除[beg,end)区间的数据,无返回值
erase(pos);                    //删除pos位置的数据,返回下一个数据的位置
remove(elem);                  //删除容器中所有与elem值匹配的元素

可以看到这些STL的容器,封装的成员函数完成相似功能用的都是同一个函数名,这样有助于我们使用。

注意的是:知名位置进行插入和删除时,不能使用下标,而是用迭代器指明哪个位置。

6.list数据存取

front();                                          //返回第一个元素
back();                                           //返回最后一个元素

STL中的链表和《数据结构与算法》中的链表一样,不支持随机存取,所以这里没有重载[]at()的成员函数来进行访问。

7.链表反转和排序

reverse();                                             //反转链表
sort();                                                //链表排序

注意:

  • 我们之前deque的排序算法sort(beg,end)是全局函数,需要包含算法的头文件;而这里的sort()是成员函数
  • 链表的迭代器是双向迭代器,不是随机访问迭代器;所有不支持随机访问迭代器的容器,都不可以用标准算法
  • 对于不支持随机访问迭代器的容器模板类,内部往往会提供一些对应的成员方法

8.排序案例练习

案例描述:将Person自定义数据类型进行排序,Person中属性有姓名、年龄、身高
排序规则:按照年龄进行升序,如果年龄相同按照身高进行降序

#include <iostream>
#include <string>
#include <list>
using namespace std;//选手类
class Person 
{
public:Person(string name, int age,int heigh){this->m_name = name;this->m_age = age;this->m_heigh = heigh;}string m_name;int m_age;int m_heigh;
};//指定比赛规则
bool compare(Person& p1, Person& p2)
{if (p1.m_age == p2.m_age)return p1.m_heigh < p2.m_heigh;return p1.m_age < p2.m_age;
}void test01()
{list<Person> lst;Person p1("小明", 20, 180);Person p2("小红", 18, 170);Person p3("小绿", 30, 185);Person p4("小蓝", 28, 180);Person p5("小紫", 20, 175);lst.push_back(p1);lst.push_back(p2);lst.push_back(p3);lst.push_back(p4);lst.push_back(p5);lst.sort(compare);for (list<Person>::iterator it = lst.begin(); it != lst.end(); it++){cout << "姓名:" << it->m_name << "  年龄:" << it->m_age << "  身高:" << it->m_heigh << endl;}
}int main()
{test01();return 0;
}

四.set/multiset容器

1.set/multiset理解

翻译过来的意思是集合,所有元素都会在插入时自动被排序。

所以set/multiset的属于关联式容器(在进入时自动排序),底层结构是由二叉树实现的。

setmultiset的区别:

  • set不允许容器中有重复的元素
  • multiset允许容器中有重复的元素

它两的头文件都是<set>,只是在用法上区分。

2.构造与赋值

构造:

set<T> st;                      //默认构造函数
set(const set &st);             //拷贝构造函数

赋值:

set& operator=(const set &st);           //重载=

学过《数据结构与算法》,应该知道集合并不是一种线性结构,所以它不可能有区间构造,且set不允许重复元素,那么也不可能用n个同一元素赋值。

集合没有端口,所以不可能还有pushpop的操作。

3.大小和交换

size();            //返回容器中元素的数目
empty();           //交换容器是否为空
swap(st);          //交换两个集合容器

集合不存在resize()重新设定大小。

4.插入和删除

insert(elem);                   //在容器中插入元素
clear();                        //清除所有元素
erase(pos);                     //删除pos迭代器所指的元素,返回下一个元素的迭代器
erase(beg,end);                 //删除区间[beg,end)的所有元素,返回下一个元素的迭代器
erase(elem);                    //删除容器中值为elem的元素

集合没有pushpop,只有insert一种插入方式,另外它可以提供值删除。

注意:删除时集合的顺序是排序后的结果而不是插入的顺序。

5.查找和统计

find(key);                         //查找key是否存在,若存在返回该元素的迭代器;若不存在,返回set.end()
count(key);                        //统计key的元素个数

count()对于set容器的统计,结果要么是0要么是1。

6.set/multiset区别

区别:

  • set不可以插入重复数据,而multiset可以
  • set插入数据的同时会返回插入结果,表示插入是否成功
  • multiset不会检测数据,因此可以插入重复数据

这部分主要从底层原理剖析了setinsert的返回值,它的返回值是一个pair对组,第一个参数是迭代器,第二个参数是bool类型,我们可以根据bool数据判断是否插入成功。而multisetinsert函数返回的是迭代器,并不做出判断。可以转到set/multisetinsert函数定义处查看返回值类型。

7.pair对组

两种创建方式:

pair<type,type> p (value1,value2);                //类似于对组的默认构造
pair<type,type> p = make_pair(value1,value2);     //类似于对组的构造成员函数

此外,要访问pair对组的两个元素,需要使用firstsecond的成员函数。

8.set容器排序

set容器默认从小到大排序,但可以利用仿函数改变排序规则。

class Mycampare
{bool operator()(int v1,int v2){return v1>v2;}
};

经过这么多的指定排序,我们也了解到指定排序顺序有两种方式,一种是之前的全局函数,二就是现在的自定义类的重载()的仿函数,二者都是返回bool类型的值。

对于自定义的数据类型,必须自定义排序规则,才能正确插入。

五.map/multimap容器

1.map/multimap理解

map中所有元素都是pair

  • pair中第一个元素为key (键值),起到索引作用,第二个元素为value (实值)
  • 所有元素都会根据元素的键值自动排序

本质:

  • map/multimap属于关联式容器,底层结构是用二叉树实现。

优点:

  • 可以根据key值快速找到value

mapmultimap区别:

  • map不允许容器中有重复key值元素
  • multimap允许容器中有重复key值元素

2.构造和赋值

构造:

map<T1,T2> mp;                                 //默认构造函数
map(const map& mp);                            //拷贝构造函数

赋值:

map& operator=(const map& mp);                 //重载=

3.大小和交换

size();            //返回容器中元素的数目
empty();           //交换容器是否为空
swap(mp);          //交换两个集合容器

4.插入和删除

insert(elem);                   //在容器中插入元素
clear();                        //清除所有元素
erase(pos);                     //删除pos迭代器所指的元素,返回下一个元素的迭代器
erase(beg,end);                 //删除区间[beg,end)的所有元素,返回下一个元素的迭代器
erase(key);                    //删除容器中值为key的元素

我们知道map数组的元素是一个对组,所以插入时由于创建对组方式的多样性,这里的插入方式也有多样性。

m.insert(pair<int,int>(1,10));                    //第一种
m.insert(make_pair(2,20));                        //第二种
m.insert(map<int,int>::value_type(3,30));         //第三种
m[4]=40;                                          //第四种,但不建议

之所以不建议第四种,虽然map[]进行了重载,但是[]map里更多的是通过key来访问value,而不是进行插入。

5.查找和统计

find(key);                                 //查找key是否存在,若存在返回该元素的迭代器;若不存在,返回set.end()
count(key);                                //统计key的元素个数

map不允许重复插入,对于统计count()来说其结果要么是1要么是0。

6.排序

这么多的仿函数排序,应该也会了。

六.案例练习

1.案例要求

  • 公司今天招聘了10个员工 (ABCDEFGHIJ),10名员工进入公司之后
  • 需要指派员工在哪个部门工作
  • 员工信息有:姓名 工资组成;部门分为: 策划、美术、研发
  • 随机给10名员工分配部门和工资
  • 通过multimap进行信息的插入 key(部门编号)value(员工)
  • 分部门显示员工信息

2.实现步骤

  • 创建10名员工,放到vector容器中
  • 便利vector容器,取出每个员工,进行随机分组
  • 分组后,将员工部门编号作为key,具体员工为value,放到multimap容器中
  • 分部门显示员工信息

3.案例代码

#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <ctime>
using namespace std;/*部门编号:1:策划;2:美术;3:研发。
*///员工类
class Worker 
{
public:Worker(string name, int salary){this->m_name = name;this->m_salary = salary;}string m_name;int m_salary;};void creatworker(vector<Worker>& v)
{string namestd = "ABCDEFGHJK";for (int i = 0; i < 10; i++){string name = "员工";name += namestd[i];Worker worker(name, rand()%10000+10000);v.push_back(worker);}
}void setworker(vector<Worker>& v, multimap<int, Worker>& w)
{for (vector<Worker>::iterator it = v.begin(); it != v.end(); it++){int depid = rand() % 3+1;w.insert(make_pair(depid, *it));}
}void showbg(multimap<int, Worker>& w)
{cout << "策划部门的信息如下:" << endl;multimap<int, Worker>::iterator pos = w.find(1);int count1 = w.count(1);for (int index = 0; index< count1; index++,pos++){cout << "姓名:" << pos->second.m_name << "    工资:" << pos->second.m_salary << endl;}cout << "------------------" << endl;cout << "美术部门的信息如下:" << endl;pos = w.find(2);int count2 = w.count(2);for (int index = 0; index < count2; index++, pos++){cout << "姓名:" << pos->second.m_name << "    工资:" << pos->second.m_salary << endl;}cout << "------------------" << endl;cout << "研发部门的信息如下:" << endl;pos = w.find(3);int count3 = w.count(3);for (int index = 0; index < count3; index++, pos++){cout << "姓名:" << pos->second.m_name << "    工资:" << pos->second.m_salary << endl;}
}void test01()
{srand((unsigned int)time(NULL));//1.创建员工vector<Worker> v;creatworker(v);//2.进行分组multimap<int,Worker> mw;setworker(v, mw);//3.分组显示员工showbg(mw);
}int main()
{test01();return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/7007.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【精品毕设推荐】搜索引擎的设计与实现

点击免费下载原文及代码 摘要 我们处在一个大数据的时代&#xff0c;伴随着网络信息资源的庞大&#xff0c;人们越来越多地注重怎样才能快速有效地从海量的网络信息中&#xff0c;检索出自己需要的、潜在的、有价值的信息&#xff0c;从而可以有效地在日常工作和生活中发挥作…

【UnityRPG游戏制作】Unity_RPG项目之场景环境搭建和解析

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;Uni…

事件知识图谱 - EventKGE_Event knowledge graph embedding with event causal transfer

EventKGE: Event knowledge graph embedding with event causal transfer 作者&#xff1a;Daiyi Li&#xff08;南航&#xff09; 来源&#xff1a;2023 Knowledge-Based Systems&#xff08;中科院一区&#xff0c;影响因子8.8&#xff09; 论文&#xff1a;[ScienceDirec…

Linux中gcc/g++的使用

文章目录 前言gcc/g 前言 gcc和g即为编译器。其中gcc为c语言的编译器&#xff0c;只能编译c语言&#xff1b;g为c的编译器&#xff0c;既能编译c语言&#xff0c;又能编译c。 在前面的文章中&#xff0c;我们提到代码转换成可执行程序需要经过 预处理&#xff08;进行宏替换)…

一、Vagrant搭建相关环境

目录 一、创建Vagrant相关环境1.下载安装VirtualBox2.在BlOS中设置CPU虚拟化3.使用Vagrant新建linux虚拟机3.1下载Vagrant3.2Vagrant官方镜像仓库3.3使用Vagrant初始化一个centos7的虚拟机 4.设置固定ip地址 二、安装docker1.按照docker 三、docker安装一些中间件1.mysql安装2.…

从零开始学AI绘画,万字Stable Diffusion终极教程(六)

【第6期】知识补充 欢迎来到SD的终极教程&#xff0c;这是我们的第六节课&#xff0c;也是最后一节课 这套课程分为六节课&#xff0c;会系统性的介绍sd的全部功能&#xff0c;让你打下坚实牢靠的基础 1.SD入门 2.关键词 3.Lora模型 4.图生图 5.controlnet 6.知识补充 …

Linux环境创建普通用户,授权root权限。报错:usermod: group ‘sudo‘ does not exist

在Linux环境下&#xff0c;创建普通用户并授权root权限需要以下步骤&#xff1a; 1. 以root用户登录终端。 2. 执行以下命令创建一个新的用户&#xff0c;其中username为你想要创建的用户名&#xff0c;可根据实际情况自行更改。 adduser username 3. 设置该用户的密码&…

【C++】vector类的增删改查模拟实现(图例超详细解析!!!)

目录 一、前言 二、源码引入 三、vector的模拟实现 ✨实现框架 ✨前情提要 ✨Member functions —— 成员函数 ⚡构造函数 ⭐无参构造 ⭐迭代器区间构造 ⭐n个值构造 ⚡拷贝构造 ⚡运算符赋值重载 ⚡析构函数 ✨Element access —— 元素访问 ⚡operator[ ] …

VsCode插件 -- Power Mode

一、安装插件 1. 首先在扩展市场里搜索 Power Mode 插件&#xff0c;如下图 二、配置插件 设置 点击小齿轮 打上勾 就可以了 第二种设置方法 1. 安装完成之后&#xff0c;使用快捷键 Ctrl Shift P 打开命令面板&#xff0c;在命令行中输入 settings.json &#xff0c; 选择首…

通过maven命令行mvn的方式,下载依赖jar包

目录 目标步骤执行mvn命令 目标 有时通过idea-maven-reload all maven projects更新项目依赖时&#xff0c;会报错Could not find artifact xxx.xx:xxx.x:xxx.jar (https://repo1.maven.org/maven2/org/)。 此时可尝试通过mvn命令行进行依赖下载&#xff08;需要配置maven本地…

【Python深度学习(第二版)(2)】深度学习之前:机器学习简史

文章目录 一. 深度学习的起源1. 概率建模--机器学习分类器2. 早期神经网络--反向传播算法的转折3. 核方法 -- 忽略神经网络4. 决策树、随机森林和梯度提升机5. 神经网络替代svm与决策树 二. 深度学习与机器学习有何不同 可以这样说&#xff0c;当前工业界所使用的大部分机器学习…

asp.net朱勇项目个人博客(3)

引文:按照书上的项目&#xff0c;我们最后实现管理端的三个增删改查的功能即可,相对与三个增删改查&#xff0c;文章&#xff0c;分类和留言&#xff0c;这里我们所需要用的的关联的一个表就是文章表&#xff0c;因为文章表每一个文章的增加显示和修改都需要对应的一个分类&…

【Linux】网络连接配置——nmcli工具配置连接增删改查实例

nmcli工具配置连接增删改查实例 &#xff08;一&#xff09;网络连接配置基本项目1.网络接口配置2.主机名配置3.DNS服务器配置 &#xff08;二&#xff09;网络连接配置文件&#xff08;三&#xff09;网络配置方法&#xff08;四&#xff09;nmcli工具配置连接管理1.增2.查3.改…

sql编写规范(word原件)

编写本文档的目的是保证在开发过程中产出高效、格式统一、易阅读、易维护的SQL代码。 1 编写目的 2 SQL书写规范 3 SQL编写原则 软件全套资料获取进主页或者本文末个人名片直接获取。

GStreamer日志调试笔记

1、查询所有分类 #gst-launch-1.0 --gst-debug-help 2、查询videotestsrc的日志 #gst-launch-1.0 --gst-debug-help | findstr videotestsrc 结果&#xff1a; 3、使用--gst-debug设置相应日志类型的相应等级&#xff0c;越大显示日志越多&#xff0c;排查内存泄露可以设置为9 …

国内外主流大模型都具备有哪些特点?

文章目录 ⭐ 火爆全网的大模型起点⭐ 国外主流LLM及其特点⭐ 国内主流LLM及其特点⭐ 全球大模型生态的发展 该章节呢&#xff0c;我们主要是看一下关于国内外主流的大语言模型&#xff0c;通过它们都具备哪些特点&#xff0c;来达成对多模型有一个清晰的认知。对于 “多模型” …

帮助命令

1.man 原意&#xff1a;manual 所在路径&#xff1a;/usr/bin/man 执行权限&#xff1a;所有用户 语法&#xff1a;man [命令或配置文件] 功能描述&#xff1a;获得帮助信息 例&#xff1a;$ man ls 查看ls命令的帮助信息 查看命令的帮助主要是看这个命令是干什么用的&am…

Vue3+.NET6前后端分离式管理后台实战(十七)

1&#xff0c;Vue3.NET6前后端分离式管理后台实战(十七)已经在微信公众号更新&#xff0c;有兴趣的扫码关注一起交流学习。

数据治理:数据孤岛是企业信息化发展中难以避免的阶段

随着信息技术的飞速发展&#xff0c;企业对于数据的依赖程度日益加深。在这个过程中&#xff0c;数据治理成为了企业信息化建设的核心环节。然而&#xff0c;在实际操作中&#xff0c;企业往往会遇到一种难以避免的现象——数据孤岛。 一、数据孤岛的定义与成因 数据孤岛&…

电磁兼容(EMC):产品适用静电放电(ESD)标准全解

目录 1. 标准体系 2. 试验方法标准 3. 常见产品的抗扰度标准 自己研发的产品到底需要满足什么样的静电放电标准要求才是满足国家标准要求。客户提出的静电放电接触放电4kV&#xff0c;空气放电8kV要求&#xff0c;是高于国家标准要求还是低于国家标准要求&#xff1f;面对这…