从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.mfbz.cn/a/608155.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【因特网中自治系统内部的路由选择,RIP 进程处理 OSPFOSPF(Open Shortest Path First)最短路径优先协议】

文章目录 因特网中自治系统内部的路由选择RIP&#xff08;Routing Information Protocol&#xff09;内部网关协议RIP通告&#xff08;advertisements&#xff09;RIP: 链路失效和恢复RIP 进程处理OSPF(Open Shortest Path First)最短路径优先协议OSPF “高级” 特性(在RIP中的…

C++ 继承篇

面向对象语言的三大特性&#xff1a;封装&#xff0c;继承和多态 根据目前学到的知识&#xff0c;对于封装的理解&#xff0c;大致有两层&#xff1a; 将数据和方法封装&#xff0c;不想让外面看到用private/protected修饰&#xff0c;想让外面看到用public修饰类型的行为不满…

Mybatis 源码分析

《黑马架构师_源码系列-主流框架&中间件》-- MyBatis &#xff08;讲师&#xff1a;子慕&#xff09; * 手写持久层框架-仿写mybatis * Mybatis架构设计&主要组件 * Mybatis如何完成的初始化? * Mybatis如何完成的sql解析及执行? * Mybatis如何设置的参数? * Mybat…

容器集群管理系统Kubernetes(K8S)

目录 一、前言 1.1什么是云原生&#xff1f; 1.2云要素的四要素&#xff1f; 1.2.1微服务 1.2.2容器化 1.2.3DevOps 1.2.4持续交付 1.3云平台有哪些&#xff1f; 1.4SRE 二、Kubernetes 概述 2.1K8S 是什么 2.2K8S作用 2.3K8S版本 2.4为什么要用 K8S 2.5K8S 的特…

【论文阅读】Spectral–Spatial Attention Network for Hyperspectral Image Classification

Spectral–Spatial Attention Network for Hyperspectral Image Classification 论文地址摘要&#xff1a;1. 简介1.1.动机1.2.贡献 2. 相关作品2.1.双向递归网络RNN2.2.CNN2.3. Attention Mechanism 3. 方法3.1 Attention with RNN for Spectral Classification3.2&#xff0e…

【镜像仿真篇】磁盘镜像仿真常见错误

【镜像仿真篇】磁盘镜像仿真常见错误 记系统镜像仿真常见错误集—【蘇小沐】 1、实验环境 2023AFS39.E01&#xff08;Windows11系统镜像&#xff09;Arsenal Image Mounter&#xff0c;[v3.10.262]‍Vmware Workstation 17 Pro&#xff0c;[v17.5.1]Windows 11 专业工作站版…

单片机——直流电机

1 .关于4线直流电机 两根12v供电线&#xff0c;通入12v&#xff0c;风扇以最高转速工作。 一根测速线&#xff0c;电机工作时输出测速信号&#xff0c;提供转速反馈。一根PWM控制信号线&#xff0c;电机工作时控制器输入PWM控制信号&#xff0c;以控制风扇转速(通常为占空比可…

性能测试瓶颈:CPU 问题的深度分析和调优!

性能测试是评估系统、应用程序或服务的性能和稳定性的过程。在进行性能测试时&#xff0c;我们经常会发现一些瓶颈&#xff0c;其中之一就是与CPU相关的问题。CPU是计算机系统中最重要的组件之一&#xff0c;对系统的整体性能起着至关重要的作用。本文将从零开始详细介绍如何分…

【有趣的透镜】1.透镜初相识

1.透镜的外形和材料 (1)透镜由玻璃或者塑料制成&#xff1b; (2)透镜一般为圆型&#xff0c;其单面或双面为球面&#xff1b; 2.透镜的类型和折射 (1)球面外凸为凸透镜(聚光)&#xff0c;球面内凹为凹透镜(散光)&#xff1b; (2)透镜是基于光的折射&#xff0c;只要光从一…

第一批00后已经开始做家政了!2024年轻人的机会在哪里?2024创业小项目。

当代年轻人的路子到底有多野&#xff1f;江苏无锡的00后女生冯佳佳&#xff0c;觉得未来家政行业很有前景&#xff0c;便毅然决然的辞去了幼儿园老师的工作&#xff0c;和男朋友一起成立了家政公司。、 诚然&#xff0c;现在的家政收费是及其昂贵赚钱的&#xff0c;开锁师傅开一…

点击导航栏选项后,导航栏高亮该选项

如图所示&#xff0c;点击“流浪猫客栈”时&#xff0c;会一直高亮显示&#xff0c;表示现在看的是这个选项的页面。 Cat.jsp上写&#xff1a; <!--header--> <jsp:include page"header.jsp"><jsp:param name"flag" value"3">…

上位机图像处理和嵌入式模块部署(树莓派4b和c++新版本的问题)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 自己读书的时候是03年&#xff0c;学习c也是差不多04年开始&#xff0c;到现在基本上20年了。这20年过程当中&#xff0c;其实c的语言版本一直是在…

SSRF漏洞学习

1.ssrf漏洞简介 ssrf&#xff08;服务器端请求伪造&#xff09;&#xff0c;它是由攻击者构造形成的由服务端发起的一个较为安全的漏洞。 它攻击的目标是从外网无法访问的内部系统&#xff0c;因为它是从服务端发起的&#xff0c;所以它能够请求到与它相连并且与外网隔离的内部…

PXE批量部署,一键安装配置多台Linux系统

目录 一、PXE批量部署的优点 二、搭建PXE远程安装服务器 1. 实验初始化设置 2. 一键安装软件包 3. 复制 vmlinuz、initrd.img、pxelinux.0文件 4. 配置PE启动菜单配置文件 5. 修改配置文件&#xff0c; 启动各个软件服务 6. kickstart自动应答文件修改启动菜单配置文件…

【用文本生成歌声】Learn2Sing 2.0——歌声转换算法即梅尔频谱详解

一. 频谱图与梅尔谱图的介绍 频谱图&#xff1a;频谱图可以理解为一堆垂直堆叠在一起的快速傅里叶变换结果。 1.1 信号 在进入频谱图模块之前&#xff0c;首先我们需要了解信号是什么。 信号就是某一特定量随时间变化&#xff0c;对于音频来说&#xff0c;这个特定的变化量就…

java.net.SocketInputStream.socketRead0 卡死导致 tomcat 线程池打满的问题

0 TL;DR; 问题与原因&#xff1a;某些特定条件下 java.net.SocketInputStream.socketRead0 方法会卡死&#xff0c;导致运行线程一直被占用导致泄露采用的方案&#xff1a;使用监控线程异步监控卡死事件&#xff0c;如果发生直接关闭网络连接释放链接以及对应的线程 1. 问题 …

pytest教程-42-钩子函数-pytest_runtest_makereport

领取资料&#xff0c;咨询答疑&#xff0c;请➕wei: June__Go 上一小节我们学习了pytest_runtest_teardown钩子函数的使用方法&#xff0c;本小节我们讲解一下pytest_runtest_makereport钩子函数的使用方法。 pytest_runtest_makereport 钩子函数在 pytest 为每个测试生成报…

修改表空间的状态

Oracle从入门到总裁:​​​​​​https://blog.csdn.net/weixin_67859959/article/details/135209645 表空间有4种状态:联机、脱机、只读和读写。修改其中某一种状态的语句如下所示 设置表空间 tspace 为联机状态。 SQL>ALTER TABLESPACE space ONLINE: 设置表空间 tspa…

Python运维之多线程!!

一、多线程 二、多线程编程之threading模块 2.1、使用threading进行多线程操作有两种方法&#xff1a; 三、多线程同步之Lock&#xff08;互斥锁&#xff09; 四、多线程同步之Semaphore&#xff08;信号量&#xff09; 五、多线程同步之Condition 六、多线程同步之Event…
最新文章