STL之deque容器代码详解

1 基础概念

功能:

双端数组,可以对头端进行插入删除操作。

deque与vector区别:

  • vector对于头部的插入删除效率低,数据量越大,效率越低。

  • deque相对而言,对头部的插入删除速度回比vector快。

  • vector访问元素时的速度会比deque快,这和两者内部实现有关。

在这里插入图片描述

deque内部工作原理:

  • deque内部有个中控器,维护每段缓冲区中的内容,缓冲区中存放真实数据。

  • 中控器维护的是每个缓冲区的地址,使得使用deque时像一片连续的内存空间。

  • deque容器的迭代器也是支持随机访问的。

在这里插入图片描述

2 代码解释

Talk is cheap, show me the code.

#include<iostream>
using namespace std;
#include<deque>
#include<algorithm>void printDeque(const deque<int>& dd)
{//注意这里的只读迭代器的操作for (deque<int>::const_iterator it = dd.begin(); it != dd.end(); it++){cout << *it << " ";}cout << endl;
}/*
构造函数原型:
deque<T> deqT; //默认构造形式
deque(beg, end); //构造函数将[beg, end)区间中的元素拷贝给本身。
deque(n, elem); //构造函数将n个elem拷贝给本身。
deque(const deque &deq); //拷贝构造函数
*/void test01()
{deque<int> d1;for (int i = 0; i < 10; i++){d1.push_back(i);}printDeque(d1);deque<int> d2(d1.begin(), d1.end());printDeque(d2);deque<int> d3(10, 88);printDeque(d3);deque<int> d4(d3);printDeque(d4);}/*
赋值函数原型:
deque& operator=(const deque &deq); //重载等号操作符
assign(beg, end); //将[beg, end)区间中的数据拷贝赋值给本身。
assign(n, elem); //将n个elem拷贝赋值给本身。
*/void test02()
{deque<int> d1;for (int i = 0; i < 10; i++){d1.push_back(i);}deque<int> d2;d2 = d1;printDeque(d2);deque<int> d3;d3.assign(d2.begin(), d2.end());printDeque(d3);deque<int> d4;d4.assign(10, 88);printDeque(d4);
}/*
大小操作函数原型:
deque.empty(); //判断容器是否为空
deque.size(); //返回容器中元素的个数
deque.resize(num); //重新指定容器的长度为num,若容器变长,则以默认值填充新位置。
//如果容器变短,则末尾超出容器长度的元素被删除。
deque.resize(num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置。
//如果容器变短,则末尾超出容器长度的元素被删除。
*/// 我们发现跟vector相比没有了capacity容量相关的操作,因为可以无限地扩展,只需要有一段地址来维护空间void test03()
{deque<int> d1;for (int i = 0; i < 10; i++){d1.push_back(i);}printDeque(d1);if (d1.empty()){cout << "EMPTY" << endl;}else{cout << d1.size() << endl;}d1.resize(20, 999);printDeque(d1);
}/*
插入和删除函数原型:
两端插入操作:
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位置的数据,返回下一个数据的位置。
*/void test04()
{deque<int> d1;d1.push_back(100);d1.push_back(100);d1.push_back(100);d1.push_back(100);d1.push_back(100);d1.push_back(100);printDeque(d1);d1.push_front(200);printDeque(d1);d1.pop_back();printDeque(d1);d1.pop_front();printDeque(d1);d1.insert(d1.begin() + 2, 5, 1000);printDeque(d1);d1.insert(d1.end() - 1, d1.begin(), d1.end());printDeque(d1);d1.erase(d1.begin()+1);printDeque(d1);d1.clear();printDeque(d1);}/*
数据存取函数原型:
at(int idx); //返回索引idx所指的数据
operator[]; //返回索引idx所指的数据
front(); //返回容器中第一个数据元素
back(); //返回容器中最后一个数据元素
*/void test05()
{deque<int> d1;for (int i = 0; i < 10; i++){d1.push_back(i);}printDeque(d1);cout << d1.at(2) << endl;cout << d1[2] << endl;cout << d1.front() << endl;cout << d1.back() << endl;
}/*
排序算法:
sort(iterator beg, iterator end) //对beg和end区间内元素进行排序
*/void test06()
{deque<int> d1;d1.push_back(10);d1.push_back(20);d1.push_back(15);d1.push_front(89);d1.push_front(78);d1.push_front(99);printDeque(d1);sort(d1.begin(), d1.end());printDeque(d1);
}int main()
{test01();test02();test03();test04();test05();test06();system("pause");return 0;
}

3 应用场景

C++标准模板库(STL)中的deque(双端队列)容器是一种支持在两端高效插入和删除操作的数据结构。它在实际项目中有许多应用场景,其中一些例子包括:

  1. 任务调度队列: 在多线程或并发编程中,deque可以用作任务调度队列。新任务可以在队列的前端或后端插入,而工作线程可以从队列的另一端获取任务执行。这种方式允许高效的任务调度和分发。

    #include <deque>
    #include <mutex>
    #include <thread>std::deque<Task> taskQueue;
    std::mutex queueMutex;void AddTask(const Task& task) {std::lock_guard<std::mutex> lock(queueMutex);taskQueue.push_back(task);
    }Task GetTask() {std::lock_guard<std::mutex> lock(queueMutex);Task task = taskQueue.front();taskQueue.pop_front();return task;
    }
    
  2. 实时数据流处理: 在需要高性能数据流处理的应用中,deque可以用于缓存数据,支持快速的数据插入和删除。这对于实时数据处理系统(如金融数据处理或传感器数据处理)非常有用。

    #include <deque>
    #include <iostream>void ProcessData(std::deque<Data>& dataQueue) {// 实时数据处理逻辑while (!dataQueue.empty()) {Data currentData = dataQueue.front();dataQueue.pop_front();// 处理数据...}
    }
    
  3. 存储历史记录: 在需要保留最近N个元素的场景中,deque可以用于实现一个固定大小的历史记录缓存。新元素可以从一端插入,而旧元素可以从另一端删除,以保持缓存的大小。

    #include <deque>
    #include <iostream>const int MaxHistorySize = 10;
    std::deque<Record> historyDeque;void AddToHistory(const Record& record) {historyDeque.push_back(record);if (historyDeque.size() > MaxHistorySize) {historyDeque.pop_front();}
    }
    
  4. 实现高效的双端队列: 当需要在两端执行频繁插入和删除操作时,使用deque而不是vector可能更为高效,因为deque的设计允许在两端进行快速操作,而vector在插入或删除头部元素时的性能较差。

总的来说,deque是一个灵活的数据结构,适用于许多不同的应用场景,其中需要高效支持两端操作的情况。

4 实际用例

下面是一个简单的示例,演示了使用deque相对于vector在频繁插入和删除操作时的优势。这个示例模拟一个实时日志系统,其中日志消息被不断添加到队列,并定期删除旧的日志消息,以保持队列的大小。

#include <iostream>
#include <deque>
#include <ctime>
#include <cstdlib>struct LogMessage {std::string message;time_t timestamp;
};class RealTimeLogger {
public:void AddLog(const std::string& message) {LogMessage log;log.message = message;log.timestamp = std::time(nullptr);logQueue.push_back(log);}void PruneOldLogs() {const int MaxLogCount = 5;while (logQueue.size() > MaxLogCount) {logQueue.pop_front();}}void PrintLogs() {for (const auto& log : logQueue) {std::cout << "[" << log.timestamp << "] " << log.message << std::endl;}std::cout << std::endl;}private:std::deque<LogMessage> logQueue;
};int main() {RealTimeLogger logger;// 模拟日志生成for (int i = 0; i < 10; ++i) {logger.AddLog("Log message #" + std::to_string(i));logger.PruneOldLogs();logger.PrintLogs();}return 0;
}

在这个示例中,RealTimeLogger类使用deque作为存储日志消息的容器。在每次添加日志消息时,它会执行PruneOldLogs方法来删除旧的消息,以保持队列的大小。由于deque支持在两端高效地进行插入和删除操作,这个实现在频繁添加和删除日志消息时的性能表现更好。

当使用vector时,由于在头部删除元素的代价相对较高,性能可能不如deque。在实际项目中,这种优势可能在需要处理大量实时数据的场景下更为明显,例如日志记录、事件处理等。

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

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

相关文章

【Node.js】-闲聊:前端框架发展史

前端框架的发展史是一个不断演进和创新的过程&#xff0c;旨在提高开发效率、优化用户体验&#xff0c;并推动前端技术的不断发展。以下是前端框架发展的主要阶段和关键里程碑&#xff1a; 早期阶段&#xff1a; 在这个阶段&#xff0c;前端主要由HTML、CSS和JavaScript等基础技…

解决ChatGPT发送消息没有反应

ChatGPT发消息没反应 今天照常使用ChatGPT来帮忙码代码&#xff0c;结果发现发出去的消息完全没有反应&#xff0c;即不给我处理&#xff0c;也没有抱任何的错误&#xff0c;按浏览器刷新&#xff0c;看起来很正常&#xff0c;可以查看历史对话&#xff0c;但是再次尝试还是一…

计算机视觉——P2PNet基于点估计的人群计数原理与C++模型推理

简介 人群计数是计算机视觉领域的一个核心任务&#xff0c;旨在估算静止图像或视频帧中的行人数量。在过去几十年中&#xff0c;研究人员在这个领域投入了大量的精力&#xff0c;并在提高现有主流基准数据集性能方面取得了显著进展。然而&#xff0c;训练卷积神经网络需要大规…

【Java.mysql】——增删查改(CRUD)之 增查(CR) 附加数据库基础知识

目录 &#x1f6a9;数据库操作 &#x1f388;创建数据库 &#x1f388;使用数据库 &#x1f388;删除数据库 &#x1f6a9;数据类型 &#x1f6a9;表的操作 &#x1f388;创建表 &#x1f308;查看表结构 &#x1f388;删除表 ❗练习(综合运用) &#x1f5a5;️新增…

腾讯面经学习笔记

&#x1f496; 前言 &#x1f469;‍&#x1f3eb; 参考地址 &#x1f496; 操作系统 1. 进程和线程的区别 本质区别 进程是操作系统资源分配的基本单位线程是任务调度和执行的基本单位 开销方面 每个进程都有独立的代码和数据空间&#xff08;程序上下文&#xff09;&#…

Matlab|【EI复现】电动汽车集群并网的分布式鲁棒优化调度模型

目录 1 内容简介 2 关键知识点 2.1 三类电动汽车模型 3 程序结果 4 下载链接 1 内容简介 电动汽车的数据模型种类繁多&#xff0c;但是用到比较高阶数学方法的并不多&#xff0c;本次分享的程序是下图所示的文章。 采用分布鲁棒优化模型&#xff0c;用到鲁棒对等转换&…

初识Python(helloworld、海洋距离单位换算、打印名片、文本进度条、判断水仙花数)

一、Python3的安装&#xff0c;IDLE的使用&#xff1a;使用print函数输出”hello world”&#xff1b; 二、 PyCharm的安装与使用&#xff1a;创建”hello_world.py”文件并使用print函数输出”hello world” 三、海洋单位距离换算 要求&#xff1a;运行代码&#xff0c;控制台…

德国史托斯 KARL STORZ tricam SLII telecam SLII SCBI thermoflator xenen 300 维修

德国史托斯 KARL STORZ tricam SLII telecam SLII SCBI thermoflator xenen 300 维修

空间复杂度的OJ练习——轮转数组

旋转数组OJ链接&#xff1a;https://leetcode-cn.com/problems/rotate-array/ 题目&#xff1a; 思路&#xff1a; 通过题目我们可以知道这是一个无序数组&#xff0c;只需要将数组中的数按给定条件重新排列&#xff0c;因此我们可以想到以下几种方法&#xff1a; 1.暴力求解法…

docker-compose这下会用了吗?

概要 默认的模板文件是 docker-compose.yml&#xff0c;其中定义的每个服务可以通过 image 指令指定镜像或 build 指令&#xff08;需要 Dockerfile&#xff09;来自动构建。 注意如果使用 build 指令&#xff0c;在 Dockerfile 中设置的选项(例如&#xff1a;CMD, EXPOSE, V…

arduino安装索尼spresense开发库

arduino安装索尼spresense开发库 一.库安装二.库文件下载1.直接下载2.git下载1.git加速下载2.git下载加速3.将文件导入arduino 一.库安装 打开arduino点击文件->首选项 将以下链接添加进附加开发板管理器网址 https://github.com/sonydevworld/spresense-arduino-compatib…

思科网络中如何配置标准ACL协议

一、什么是标准ACL协议&#xff1f;有什么作用及配置方法&#xff1f; &#xff08;1&#xff09;标准ACL&#xff08;Access Control List&#xff09;协议是一种用于控制网络设备上数据流进出的协议。标准ACL基于源IP地址来过滤数据流&#xff0c;可以允许或拒绝特定IP地址范…