C++专题--标准模板库STL

news2024/11/25 18:25:23

c++专题-标准模板库STL

  • 1   标准模板库概述
  • 2   序列式容器
    •   2.1 vector 容器
    •   2.2 deque 容器
    •   2.3 list 容器
  • 3   关联式容器
  • 4   无序关联容器
  • 5   容器适配器
    •   5.1 STL容器适配器的种类
    •   5.2 stack容器适配器
    •   5.3 queue容器适配器
    •   5.3 priority_queue容器适配器

1   标准模板库概述

STL,英文全称 standard template library,中文可译为标准模板库或者泛型库,其包含有大量的模板类和模板函数,是 C++ 提供的一个基础模板的集合,用于完成诸如输入/输出、数学计算等功能

容器的分类

在这里插入图片描述

2   序列式容器

  2.1 vector 容器

  2.2 deque 容器

  2.3 list 容器

STL list 容器,又称双向链表容器,即该容器的底层是以双向链表的形式实现的。这意味着,list 容器中的元素可以分散存储在内存空间里,而不是必须存储在一整块连续的内存空间中 st 容器中各个元素的前后顺序是靠指针来维系的,每个元素都配备了 2 个指针,分别指向它的前一个元素和后一个元素。其中第一个元素的前向指针总为 null,因为它前面没有元素;同样,尾部元素的后向指针也总为 null。

基于这样的存储结构,list 容器具有一些其它容器(array、vector 和 deque)所不具备的优势,即它可以在序列已知的任何位置快速插入或删除元素(时间复杂度为O(1))。并且在 list 容器中移动元素,也比其它容器的效率高

  1. list 容器的创建
/**
 *
 * list 相关的方法测试
 * @brief AdapterTest::listTest
 * @return
 */
int32 AdapterTest::listTest()
{
    // 创建一个没有任何元素的空list容器
    std::list<int32> li1;

    // 创建一个包含n个元素的list容器
    std::list<int32> li2(10);

    // 创建一个包含n个元素的list容器,并为每个元素指定初始值
    std::list<int32> li3(10,8);

    // 在已有 list 容器的情况下,通过拷贝该容器可以创建新的list容器
    std::list<int32> li4(li3);// 采用此方式,必须保证新旧容器存储的元素类型一致


    std::list<int32> testList;
    for(int i = 0; i < 100;i+=10){
        if ((i & 1) == 0){
            testList.push_back(i);
        }
    }

    cout << "size : " << testList.size() << endl;
    // begin()  返回指向容器中第一个元素的双向迭代器
    // end()    返回指向容器中最后一个元素所在位置的下一个位置的双向迭代器
    std::list<int32>::iterator iter = testList.begin();
    // 1.遍历
    cout << "------using iterator to travelsal list begin------" << endl;
    for(;iter != testList.end();++iter)
    {
        cout << *iter << " ";
    }
    cout << endl;
    cout << "------using iterator to travelsal list end------" << endl;

    // const_iterator cbegin() 也可以换成 begin()  cend() 也可以换成 end()
    std::list<int32>::const_iterator citer = testList.cbegin();
    cout << "------using const_iterator to travelsal list begin------" << endl;
    for(;citer != testList.cend();++citer)
    {
        cout << *citer << " ";
    }
    cout << endl;
    cout << "------using const_iterator to travelsal list end------" << endl;

    // 反向迭代器 rbegin() rend()
    cout << "------using reverse_iterator to travelsal list begin------" << endl;
    //  std::list<int32>::const_reverse_iterator 使用这个也可以
    std::list<int32>::reverse_iterator riter = testList.rbegin();

    for(;riter != testList.rend();++ riter)
    {
        cout << *riter << " ";
    }
    cout << endl;
    cout << "------using reverse_iterator to travelsal list end------" << endl;

    cout << "empty : " << testList.empty() << endl;

    cout << "size : " << testList.size() << endl;

    // 返回第一个元素的引用
    cout << "front : " << testList.front() << endl;

    // 返回最后一个元素的引用
    cout << "back : " << testList.back() << endl;

    // 在容器尾部插入一个元素
    testList.push_back(766);
    cout << "back : " << testList.back() << endl;
    // 删除容器尾部的一个元素 无返回值

    testList.pop_back();

    // 在容器中的指定位置插入元素。该函数和insert()功能相同,但效率更高
    testList.emplace(testList.end(),800);
    cout << "back : " << testList.back() << endl;

    // insert() 在容器中的指定位置插入元素
    testList.insert(testList.begin(),900);
    cout << "front : " << testList.front() << endl;

    // 删除指定区间的元素 返回指向下一个元素的迭代器
    iter = testList.erase(testList.begin());
    cout << *iter << endl;
}

  1. list 遍历删除元素
int32 AdapterTest::listRemoveTest()
{
    std::list<int32> testList;

    for(int i = 0;i<100;++i){
        testList.push_back(i);
    }

    std::list<int32>::const_iterator iter = testList.begin();
    for (;iter != testList.end();++iter)
    {
        cout << *iter << " ";
    }
    cout << endl;

    for(iter = testList.begin();iter != testList.end();)
    {
        if((*iter & 1) == 0)
        {
            // 删除 iter 指向的元素 并返回指向下一个元素的迭代器
            iter = testList.erase(iter);
        } else {
            ++iter;
        }
    }

    cout << "------------------------------" << endl;
    iter = testList.begin();
    for (;iter != testList.end();++iter)
    {
        cout << *iter << " ";
    }
    cout << endl;
}



3   关联式容器

4   无序关联容器

5   容器适配器

  5.1 STL容器适配器的种类


公共的头文件部分commondef.h

#ifndef COMMONDEF_H
#define COMMONDEF_H
#include <iostream>
#include <array>
#include <vector>
#include <string>
#include <iostream>
#include <algorithm>
#include <map>
#include <utility> // pair 类模板定义在<utility>头文件中
#include <set>
#include <cstring>
#include <typeinfo>
#include <deque>
#include <list>
#include <forward_list>

#define TABLE_NUM 14
#define AISTD std::
#define TABLE_NAME_LEN 128
const char PATH_SEPARATOR = '/';
#define  DATE_CHANGE_NUM 1000000LL
#define BUFFER_SIZE 1024
#define LINE cout << "********************************************************" << endl;
#define LINEFEED cout << endl;
#define FUNCTION_BEGIN  \
    cout << __FILE__ << ":" <<  __LINE__ << ":" << __FUNCTION__ << " : begin >>> " << endl;
#define FUNCTION_END \
    cout << __FILE__ << ":" <<  __LINE__ << ":" << __FUNCTION__ << " : end >>> " << endl;

typedef std::string aistring;
typedef int int32;
typedef long long int64;
typedef short int int16;
using namespace std;

#endif // COMMONDEF_H

简单的理解容器适配器,其就是将不适用的序列式容器(包括 vector、deque 和 list)变得适用。容器适配器的底层实现和模板 A、B 的关系是完全相同的,即通过封装某个序列式容器,并重新组合该容器中包含的成员函数,使其满足某些特定场景的需要。

STL 提供了 3 种容器适配器,分别为 stack 栈适配器、queue 队列适配器以及 priority_queue 优先权队列适配器。其中,各适配器所使用的默认基础容器以及可供用户选择的基础容器

容器适配器基础容器筛选条件默认使用的基础容器
stack 基础容器需包含以下成员函数: empty()   size() back() push_back() pop_back() 满足条件的基础容器有 vector、deque、listdeque
queue 基础容器需包含以下成员函数: empty() size() front() back() push_back() pop_front() 满足条件的基础容器有 deque、listdeque
priority_queue 基础容器需包含以下成员函数: empty() size() front() push_back() pop_back() 满足条件的基础容器有vector、dequevector

  5.2 stack容器适配器

stack容器适配器的创建

/**
 *
 *  stack使用的基础容器有 :
 *      - vector
 *      - list
 *      - deque (默认)
 * @brief AdapterTest::stackTest
 * @return
 *
 */
int32 AdapterTest::stackTest()
{
   // 创建一个不包含任何元素的 stack 适配器,并采用默认的 deque 基础容器
   stack<int32> s1;
   // 使用基础容器list来初始化 stack 适配器,只要该容器的类型和 stack 底层使用的基础容器类型相同即可
   stack<int32,list<int32>> s2;

   for(int i = 0;i < 10;++i)
   {
     // 压栈
     s1.push(i);
   }

   if(!s1.empty())
   {
      // 栈顶元素
      cout << "top : " << s1.top() << endl;
      // 栈中元素的个数
      cout << "size : " << s1.size() << endl;
   }

   while(!s1.empty()){
       std::cout << s1.top() << " ";
       s1.pop();
   }
   std::cout << endl;
   return 0;
}

  5.3 queue容器适配器

stack 栈容器适配器不同,queue 容器适配器有 2 个开口,其中一个开口专门用来输入数据,另一个专门用来输出数据

最先进入 queue 的元素,也可以最先从 queue 中出来,即用此容器适配器存储数据具有“先进先出(简称 “FIFO” )”的特点,因此 queue 又称为队列适配器。

queue适配器的创建及常用成员函数

int32 AdapterTest::queueTest()
{
    // 创建一个空的 queue 容器适配器,其底层使用的基础容器选择默认的 deque 容器
    queue<int32> q1;
    // 创建了一个使用 list 容器作为基础容器的空 queue 容器适配器
    queue<int32,list<int32>> q2;

    // 用基础容器来初始化 queue 容器适配器,只要该容器类型和 queue 底层使用的基础容器类型相同即可
    std::deque<int32> values{1,6,7,10,12};
    queue<int32> q3(values);

    /**
      * queue支持的成员函数
      * - empty()
      * - front() 返回queue中第一个元素的引用.如果queue是常量,就返回一个常引用;如果queue为空,返回值是未定义的
      * - back()  返回queue中最后一个元素的引用.如果queue是常量,就返回一个常引用;如果 queue 为空,返回值是未定义的
      * - push()  在queue的尾部添加一个元素的副本.这是通过调用底层容器的成员函数push_back()来完成的.
      * - pop()   删除 queue 中的第一个元素
      */
    cout << "empty : " << q3.empty() << endl;

    int32& val = q3.front();
    cout << "val : " << val << endl;

    val = q3.back();
    cout << "val : " << val << endl;

    q3.push(20);
    val = q3.back();
    cout << "val : " << val << endl;

    while (! q3.empty())
    {
        cout << "front ele " << q3.front() << endl;
        q3.pop();
    }
    return 0;
}

  5.3 priority_queue容器适配器

priority_queue 容器适配器模拟的也是队列这种存储结构,即使用此容器适配器存储元素只能“从一端进(称为队尾),从另一端出(称为队头)”,且每次只能访问 priority_queue 中位于队头的元素

但是,priority_queue 容器适配器中元素的存和取,遵循的并不是 “First in,First out”(先入先出)原则,而是"First in,Largest out"原则。直白的翻译,指的就是先进队列的元素并不一定先出队列,而是优先级最大的元素最先出队列

priority_queue 容器适配器为了保证每次从队头移除的都是当前优先级最高的元素,每当有新元素进入,它都会根据既定的排序规则找到优先级最高的元素,并将其移动到队列的队头;同样,当 priority_queue 从队头移除出一个元素之后,它也会再找到当前优先级最高的元素,并将其移动到队头

基于 priority_queue 的这种特性,因此该容器适配器有被称为优先级队列

template <typename T,
        typename Container=std::vector<T>,
        typename Compare=std::less<T> >
class priority_queue{
    //......
}

typename T:指定存储元素的具体类型;
typename Container:指定 priority_queue底层使用的基础容器,默认使用 vector 容器
typename Compare:指定容器中评定元素优先级所遵循的排序规则,默认使用std::less<T>按照元素值从大到小进行排序,还可以使用std::greater<T>按照元素值从小到大排序,但更多情况下是使用自定义的排序规则

  1.   priority_queue创建的几种方式

由于 priority_queue 容器适配器模板位于头文件中,并定义在 std 命名空间里,因此在试图创建该类型容器之前,程序中需包含以下 2 行代码:

#include <queue>
using namespace std;
/**
 * priority_queue 使用的基础容器
 *  - vector (默认)
 *  - dequeu
 * @brief AdapterTest::priorityQueueTest
 * @return
 */
int32 AdapterTest::priorityQueueTest()
{
    // 创建一个空的priority_queue容器适配器,底层采用默认的vector容器,排序方式也采用默认的std::less<T>方法
    std::priority_queue<int32> pq;

    // 可以使用普通数组或其它容器中指定范围内的数据,对priority_queue容器适配器进行初始化:
    int values[]{20,30,90,17,23,45};//使用普通数组
    std::priority_queue<int32> q1(values,values+5);

    std::vector<int32> v1{100,78,32,87,49,23};//使用向量
    std::priority_queue<int32> q2(v1.begin(),v1.end());

    // 指定优先级队列的底层排序规则 小的排在前面
    std::priority_queue<int32,std::deque<int32>,std::greater<int32>> q3(v1.begin(),v1.end());
    /**
      * priority_queue提供的成员函数
      *     - empty()   如果 priority_queue 为空的话,返回 true;反之,返回 false
      *     - size()    返回 priority_queue 中存储元素的个数
      *     - top()     返回 priority_queue 中第一个元素的引用形式
      *     - push(const T& obj)
      *       根据既定的排序规则,将元素 obj 的副本存储到 priority_queue 中适当的位置。
      *     - push(T&& obj)
      *       根据既定的排序规则,将元素 obj 移动存储到 priority_queue 中适当的位置
      *     - pop()
      *       移除 priority_queue 容器适配器中第一个元素
      *     - swap(priority_queue<T>& other)
      *         将两个priority_queue容器适配器中的元素进行互换,
      *         需要注意的是,进行互换的2个priority_queue容器
      *         适配器中存储的元素类型以及底层采用的基础容器类型
      *         都必须相同
      */
    cout << "size : " << q3.size() << endl;
    while (!q3.empty())
    {
        cout << q3.top() << " ";
        q3.pop();
    }
    cout << endl;

    cout << "---------------------q2---------------------" << endl;
    cout << "size : " << q2.size() << endl;
    while (!q2.empty())
    {
        cout << q2.top() << " ";
        q2.pop();
    }
    cout << endl;

    int32 nums[]{10,34,56,89,78,20};
    std::priority_queue<int32> q4(nums,nums+5);
    q2.swap(q4);
    cout << "---------------------q2---------------------" << endl;
    while (!q2.empty())
    {
        cout << q2.top() << " ";
        q2.pop();
    }
    cout << endl;
    return 0;
}

  1. priority_queue容器适配器实现自定义排序
      无论 priority_queue 中存储的是基础数据类型(int、double 等),还是 string 类对象或者自定义的类对象,都可以使用函数对象的方式自定义排序规则
template <typename T>
// 函数对象类
class IntegerComp
{
public:
    IntegerComp() {}
    //重载()
    bool operator()(const T& l,const T& r)
    {
        return l < r;
    }
};

上面的 class关键字也可以使用 struct关键字替代

// 函数对象类
template <typename T>
struct IntegerComp
{
public:
    IntegerComp() {}
    //重载()
    bool operator()(const T& l,const T& r)
    {
        return l > r;
    }
};

自定义优先级 coding

/**
 *
 *
 * 优先级队列自定义排序规则
 * @brief AdapterTest::priorityQueueCustomerTest
 * @return
 */
int32 AdapterTest::priorityQueueCustomerTest()
{
   int values[]{10,6,23,78,87,90};
   // l < r 时升序
   // l > r 时降序
   std::priority_queue<int32,std::deque<int32>,IntegerComp<int32>> prioQueue(values,values + 6);

   cout << "------------prioQueue: ------------" << endl;

   while(! prioQueue.empty())
   {
       cout << prioQueue.top() << " ";
       prioQueue.pop();
   }
   cout << endl;
}

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

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

相关文章

Mac RN环境搭建

RN ios android原生环境搭建有时候是真恶心&#xff0c;电脑环境不一样配置也有差异。 我已经安装官网的文档配置了ios环境 执行 npx react-nativelatest init AwesomeProject 报错 然后自己百度查呀执行 gem update --system 说是没有权限&#xff0c;执行失败。因为Mac…

SQL Server2019安装后使用SQL Server身份验证登录失败

错误情况 今天在电脑安装SQL Server2019和SMMS&#xff0c;安装过程一切顺利&#xff0c;但是在使用SMMS连接数据库时出现了异常。使用"Window 身份验证"登录时正常&#xff0c;但是如果改为使用"SQL Server 身份验证"登录时却连接失败&#xff01; 解决方…

两张图搞定前端面试特别常重要的知识点:defer和async的区别

渲染引擎解析<script>的过程 <script>标签上有defer或async属性&#xff0c;脚本就会异步加载。渲染引擎遇到这一行命令&#xff0c;就会开始下载外部脚本&#xff0c;但不会等它下载和执行&#xff0c;而是直接执行后面的命令&#xff1b;默认情况是渲染引擎遇到…

微信开发之一键扫码入群的技术实现

好友将群二维码发送给机器人&#xff0c;机器人调用本接口将自动识别入群 请求URL&#xff1a; http://域名地址/scanJoinRoom 请求方式&#xff1a; POST 请求头Headers&#xff1a; Content-Type&#xff1a;application/jsonAuthorization&#xff1a;login接口返回 …

MS2692宽带低噪声放大器

MS2692 是一款宽带低噪声放大器&#xff0c;工作频率 0.45GHz  5.0GHz 。 具有高线性度、低噪声、带内增益平坦等特点。在 0.85GHz  4.0GHz 频带内&#xff0c;增益波动小于 3dB 。在 0.85GHz  5.0GHz 频带内&#xff0c;噪声系数 小于 1.2dB 。内部集成偏…

文件批量改名高手:轻松删除文件名,仅保留编号!

您是否经常需要对大量文件进行命名调整&#xff1f;是否为繁琐的手动操作而感到厌烦&#xff1f;现在&#xff0c;我们的智能批量文件改名工具为您提供了一种简单而高效的解决方案&#xff01;只需几步操作&#xff0c;您就能轻松删除原有的文件名&#xff0c;仅保留编号&#…

Oracle-如何判断字符串包含中文字符串(汉字),删除中文内容及保留中文内容

今天遇见一个问题需要将字段中包含中文字符串的筛选出来 --建表 CREATE TABLE HADOOP1.AAA ( ID VARCHAR2(255) ); --添加字段INSERT INTO HADOOP1.AAA(ID)VALUES(理解);....--查询表内容SELECT * FROM HADOOP1.AAA;在网上查找了一下有以下三种方式&#xff1a; 第一种&#…

新的 Python URL 解析漏洞可能导致命令执行攻击

Python URL 解析函数中的一个高严重性安全漏洞已被披露&#xff0c;该漏洞可绕过 blocklist 实现的域或协议过滤方法&#xff0c;导致任意文件读取和命令执行。 CERT 协调中心&#xff08;CERT/CC&#xff09;在周五的一份公告中说&#xff1a;当整个 URL 都以空白字符开头时&…

智慧建筑工地平台,通过信息化技术、物联网、人工智能技术,实现对施工全过程的实时监控、数据分析、智能管理和优化调控

智慧工地是指通过信息化技术、物联网、人工智能技术等手段&#xff0c;对建筑工地进行数字化、智能化、网络化升级&#xff0c;实现对施工全过程的实时监控、数据分析、智能管理和优化调控。智慧工地的建设可以提高工地的安全性、效率性和质量&#xff0c;降低施工成本&#xf…

BBS-个人博客项目完整搭建、BBS多人博客项目基本功能和需求、项目程序设计、BBS数据库表结构设计、创建BBS表模型

一、BBS-个人博客项目完整搭建 项目开发流程 一、项目分类 现在互联网公司需要开发的主流web项目一般分为两类&#xff1a;面向互联网用户&#xff0c;和公司内部管理。面向互联网用户: C(consumer)端项目 公司内部管理&#xff1a;B(business)端项目还有一类web应用&#xff…

jeecg-boot批量导入问题注意事项

现象&#xff1a; 由于批量导入数据速度很快&#xff0c; 因为数据库中的create time字段的时间可能一样&#xff0c;并且jeecg框架自带的是根据生成时间排序&#xff0c; 因此在前端翻页查询的时候&#xff0c;数据每次排序可能会不一样&#xff0c; 会出现第一页已经出现过一…

Qt读写Excel--QXlsx编译为静态库2

1、概述&#x1f954; 在使用QXlsx时由于源码文件比较多&#xff0c;如果直接加载进项目里面&#xff0c;会增加每次编译的时间&#xff1b; 直接将源码加载进项目工程中&#xff0c;会导致项目文件非常多&#xff0c;结构变得更加臃肿&#xff1b; 所以在本文中将会将QXlsx编译…

三维可视化平台有哪些?Sovit3D可视化平台怎么样?

随着社会经济的发展和数字技术的进步&#xff0c;互联网行业发展迅速。为了适应新时代社会发展的需要&#xff0c;大数据在这个社会经济发展过程中随着技术的进步而显得尤为重要。同时&#xff0c;大数据技术的快速发展进程也推动了可视化技术的飞速发展&#xff0c;国内外各类…

vue中封装自动计算比例滑块

此插件为另一位漂亮的前端同事小姐姐封装,觉得非常好用于是决定记载下来,便于复用 如图需要动态传入需要分配权重的数组,平均分配可以自动将100%平均分给数组中的值 如果手动拖拽,则会自动计算可拖动最大区域,便于最终总权重必定为100% <el-alert class"merge-alert&…

【深度学习 | 梯度那些事】 梯度爆炸或消失导致的模型收敛困难?挑战与解决方案一览, 确定不来看看?

&#x1f935;‍♂️ 个人主页: AI_magician &#x1f4e1;主页地址&#xff1a; 作者简介&#xff1a;CSDN内容合伙人&#xff0c;全栈领域优质创作者。 &#x1f468;‍&#x1f4bb;景愿&#xff1a;旨在于能和更多的热爱计算机的伙伴一起成长&#xff01;&#xff01;&…

minio 分布式文件系统主从复制

1. 在slave节点下载mc客户端工具 下载 2. 移动或复制mc文件到/usr/local/bin/文件夹 mv mc /usr/local/bin 3. 赋值权限给 mc 文件 chmod x mc 4. 查看mc客户端版本,看是否可用 #控制台显示返回信息用下面这条 mc --version #控制台显示无返回信息用下面这条 mc --versi…

LeetCode ACM模式——二叉树篇(一)

刷题顺序及思路来源于代码随想录&#xff0c;网站地址&#xff1a;https://programmercarl.com 目录 定义二叉树 创建二叉树 利用前序遍历创建二叉树 利用数组创建二叉树 打印二叉树 144. 二叉树的前序遍历 递归遍历 迭代遍历&#xff08;利用栈&#xff09; 145. 二…

移动端预览指定链接的pdf文件流

场景 直接展示外部系统返回的获取文件流时出现了跨域问题&#xff1a; 解决办法 1. 外部系统返回的请求头中调整&#xff08;但是其他系统不会给你改的&#xff09; 2. 我们系统后台获取文件流并转为新的文件流提供给前端 /** 获取传入url文件流 */ GetMapping("/get…

43 | 抖音大V人民日报粉丝数分析

背景介绍 抖音是一个面向全年龄的音乐短视频社区平台,如今已成为最火的短视频软件,无数短视频创作者通过抖音分享生活,分享技能,分享美好。其中有点赞、评论、转发、关注等功能。 我们试图分析“大 V”即粉丝数量相对较多的博主的涨粉数量和点赞、评论、转发之间的关系,…

uniapp的逆地理编码 和地理编码

1.先打开高德地图api找到那个 地理编码 2.封装好我们的请求 3.逆地理编码 和地理编码 都是固定的 记住自己封装的请求 就可以了 这个 是固定的 方式 下面这个是固定的 可以复制过去 getlocation就是uniapp提供的 获取经纬度 然后 下面的 就是高德地图提供的 方法 要想使用我…