C++入门小馆: STL 之queue和stack

嘿,各位技术潮人!好久不见甚是想念。生活就像一场奇妙冒险,而编程就是那把超酷的万能钥匙。此刻,阳光洒在键盘上,灵感在指尖跳跃,让我们抛开一切束缚,给平淡日子加点料,注入满满的passion。准备好和我一起冲进代码的奇幻宇宙了吗?Let's go!

我的博客:yuanManGan

我的专栏:C++入门小馆 C言雅韵集 数据结构漫游记  闲言碎语小记坊 题山采玉 领略算法真谛

目录

怎么使用队列和栈:

队列和栈的模拟实现:

deque:

priority_queue


先来了解

怎么使用队列和栈:

这些接口看起来已经很熟悉了。

直接来看看使用吧:

使用就很简单了。

队列和栈的模拟实现:

我们先来了解一下适配器:

适配器大家比较熟悉的就是电源适配器,我们的充电器。

queue和stack都是一种容器适配器。

我们用其他类来封装这两个容器。

我们回忆一下stack只需要在一方插入和删除,我们vector和list都能满足要求,所以我们来简单来实现一下。

#pragma once
#include<vector>
#include<list>
#include<deque>namespace refrain
{template<class T, class Container = std::deque<T>>class stack{public:T& top() {return _con.back();}const T& top() const{return _con.back();}void push(const T& x){_con.push_back(x);}void pop(){_con.pop_back();}size_t size() const{return _con.size();}bool empty(){return _con.empty();}private:Container _con;};
}

deque:

这里的缺省值给的是deque双端队列,等会再来讲解。

再来回忆一下队列,它是先进先出,一端入数据一端出数据,我们就拿头部出数据,尾部入数据,简单实现如下:

#include<deque>
#include<iostream>
using namespace std;
namespace refrain
{template<class T, class Container = std:: deque<T>>class queue{public:void push(const T& x){_con.push_back(x);}T& front(){return _con.front();}const T& front() const{return _con.front();}T& back(){return _con.back();}const T& back() const{return _con.back();}void pop(){_con.pop_front();}size_t size() const{return _con.size();}bool empty(){return _con.empty();}private:Container _con;};
}

这里我们有个问题我们的vector不是没有pop_front吗,那我们是不是不能用vector来实现队列呢?的确库里面他就是用的pop_front,库里面不想你使用vector来实现,因为vector头部操作麻烦时间复杂度高,那我们能不能强制实现呢?我们可以使用erase来实现头部删除就可以用vector来实现queue了。

这是库里实现的:

这样就适用了,但我们一般用deque这个更优秀

接下来就简单讲讲deque了:

先来对比一下list和vector的各自的优缺点:

而我们vector的优点就是list的缺点,vector的缺点就是list的优点。

优点:缺点
vector

1.支持下标随机访问,

2.CPU高速缓存命中率高

1.头部或中间位置的插入删除操作效率低下,因为要挪动数据

2.扩容有一定的成本,存在一定的浪费。比如现在容量为100满了扩成200只插入了120空间浪费了80空间。

list

1.容易位置的插入和删除的时间复杂度都是O(1),不需要挪动数据。

2.不存在扩容,按需申请释放,不浪费空间。

1.不支持下标随机访问

2.CPU高速缓存命中率低

这里补充一个知识CPU高速缓存命中率的知识:

cpu想要访问内存的一个数据,要看这个数据是否在缓存,在就缓存命中,不在就不命中;不命中就先加载到缓存,然后再访问缓存。

它加载到缓存不是只加载一个数据而是加载一个范围的数据,因为vector创建的是连续的空间,cpu的高高速缓存就高,而list每次都得先加载到缓存然后再访问缓存。

接下来就来简单了解一下deque的底层实现了。 

我们用四个指针封装deque的迭代器。

我们创建多个buff数组,用first指向buff的第一个位置,last指向最后一个位置。用cur指向当前位置。

再创建一个中控数组map,map里面存储着指向buff数组的指针,也就是二级指针。

这样设计有什么好处呢?

当我们迭代器++时

直接++cur,如果cur是最后一个的时候就移动node代码如下:

库里面是这样实现的: 

逻辑是一样的,但它的细节 处理的更好。

减减也是相同的逻辑,就不实现了。

解引用操作就很简单了

直接解引用cur。

push_back:

如果push_back时buff没有慢,就直接cur++,last++。 

当buff已经满了,我们就得创建一个buff了,让node++,然后cur指向buff的第二个元素,last指向末尾,first指向第一个元素,如图。

再来看看push_front

当buff满了,就创buff,此时我们cur不是指向第一个元素,指向的是最后一个元素,要保持连续性,node--,last,first指向尾和头。

再头插一个:

j就直接cur--就行了。

总结一下:

优点:

         1.头尾部插入删除效率很高

         2.下标随机访问效率还可以,但不如vector。

缺点:

         1.中间位置插入和删除效率一般。

         2.对比vector和list没有那么极致。(不专一)

 适合做stack和queue的适配器

priority_queue

优先级队列也不是队列是堆,堆之前我们用c语言就实现过,我们看看stl库里面怎样实现的。

我们之前实现的堆,大家回忆一下,是不是用到了大量的下标访问 ,我们就可以使用vector来当容器适配器。

当我们插入一个数50的时候,这时候还是一个堆,就不进行操作

而当我们插入35的时候:我们要进行向上调整算法。 

 

那我们回忆一下怎么找父亲节点呢?

parent = (child - 1)/ 2。

我们就写一个向下调整算法

如果c语言实现的时候认真学习的应该没有什么问题。

同样的删除堆顶时我们交换堆顶和最后一个位置,然后尾删,进行向下调整算法

我们找左右孩子怎么找到呢?

左孩子: child = parent * 2 + 1

右孩子:child = parent* 2 + 2

一样实现的轻而易举:

 我们就来实现一下堆吧:

template<class T, class Container = std::vector<T>>
class priority_queue
{
public:void push(const T& x){_con.push_back(x);adjustup(_con.size() - 1);}void pop(){std::swap(_con[0], _con[_con.size() - 1]);_con.pop_back();adjustdown(0);}const T& top() const{return _con[0];}bool empty(){return _con.empty();}//大堆void adjustup(int child){int parent = (child - 1) / 2;while (child > 0){if (_con[child] > _con[parent]){std::swap(_con[child], _con[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}}void adjustdown(int parent){int child = parent * 2 + 1;while (child < _con.size()){if (child + 1 < _con.size() && _con[child + 1] > _con[child]){child++;}if (_con[child] > _con[parent]){std::swap(_con[child], _con[parent]);parent = child;child = parent * 2 + 1;}else{break;}}}
private:Container _con;
};

 

这里的top就不能实现两个版本了,因为栈顶的元素不支持修改。 

这里还缺少一个参数是什么呢,这里可以用仿函数来实现:

仿函数

我们可以通过重载( )括号运算符来实现仿函数:

 

我们可以利用这个特性来让我们选择能创的是大堆还是小堆,但我们这个有点坑,传less创建的是小堆,我们只好按它的来哦。

#pragma once
#include<vector>
#include<iostream>namespace refrain
{template<class T>class less{public:bool operator()(const T& x, const T& y){return x < y;}};template<class T>class greater{public:bool operator()(const T& x, const T& y){return x > y;}};template<class T, class Container = std::vector<T>, class Compare = less<T>>class priority_queue{public:Compare com;void push(const T& x){_con.push_back(x);adjustup(_con.size() - 1);}void pop(){std::swap(_con[0], _con[_con.size() - 1]);_con.pop_back();adjustdown(0);}const T& top() const{return _con[0];}bool empty(){return _con.empty();}//大堆void adjustup(int child){int parent = (child - 1) / 2;while (child > 0){if (com(_con[parent], _con[child])){std::swap(_con[child], _con[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}}void adjustdown(int parent){int child = parent * 2 + 1;while (child < _con.size()){if (child + 1 < _con.size() && com(_con[child], _con[child + 1])){child++;}if (com(_con[parent], _con[child])){std::swap(_con[child], _con[parent]);parent = child;child = parent * 2 + 1;}else{break;}}}private:Container _con;};}

 完了over!

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

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

相关文章

ALTER TABLE 删除DROP表列的报错: 因为有一个或多个对象访问此列

目录 1.问题 2.解决办法 1.问题 删除某个列名的时候&#xff0c;提示错误因为有一个或多个对象访问此列 2.解决办法 2.1 添加或删除表新列名 将表中的字段设置Default 或 NOT NULL 都会给该字段添加约束&#xff0c;增加了这些约束后&#xff0c;再SQL脚本修改类型、删除会发生…

python源码打包为可执行的exe文件

文章目录 简单的方式&#xff08;PyInstaller&#xff09;特点步骤安装 PyInstaller打包脚本得到.exe文件 简单的方式&#xff08;PyInstaller&#xff09; 特点 支持 Python 3.6打包为单文件&#xff08;–onefile&#xff09;或文件夹形式自动处理依赖项 步骤 安装 PyIns…

【2025最近Java面试八股】Spring中循环依赖的问题?怎么解决的?

1. 什么是循环依赖&#xff1f; 在Spring框架中&#xff0c;循环依赖是指两个或多个bean之间相互依赖&#xff0c;形成了一个循环引用的情况。如果不加以处理&#xff0c;这种情况会导致应用程序启动失败。导致 Spring 容器无法完成依赖注入。 例如&#xff1a; Service publi…

JimuBI 积木报表 v1.9.5发布,大屏和仪表盘,免费数据可视化

项目介绍 JimuBI (积木报表BI) 是一款免费的数据可视化产品&#xff0c;含大屏和仪表盘、门户、移动图表&#xff0c;像搭建积木一样完全在线设计&#xff01; 大屏采用类word风格&#xff0c;可以随意拖动组件&#xff0c;想怎么设计怎么设计&#xff0c;可以像百度和阿里一样…

云原生课程-Docker

一次镜像&#xff0c;到处运行。 1. Docker详解&#xff1a; 1.1 Docker简介&#xff1a; Docker是一个开源的容器化平台&#xff0c;可以帮助开发者将应用程序和其依赖的环境打包成一个可移植的&#xff0c;可部署的容器。 docker daemon:是一个运行在宿主机&#xff08;DO…

HikariCP 6.3.0 完整配置与 Keepalive 优化指南

HikariCP 6.3.0 完整配置与 Keepalive 优化指南 HikariCP 是一个高性能、轻量级的 JDBC 连接池框架&#xff0c;广泛应用于 Java 应用&#xff0c;尤其是 Spring Boot 项目。本文档基于 HikariCP 6.3.0 版本&#xff0c;详细介绍其功能、配置参数、Keepalive 机制以及优化建议…

基于springboot+vue的摄影师分享交流社区的设计与实现

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

ComfyUI for Windwos与 Stable Diffusion WebUI 模型共享修复

#工作记录 虽然在安装ComfyUI for Windwos时已经配置过extra_model_paths.yaml 文件&#xff0c;但升级ComfyUI for Windwos到最新版本后发现原先的模型配置失效了&#xff0c;排查后发现&#xff0c;原来是 extra_model_paths.yaml 文件在新版本中被移动到了C盘目录下&#x…

【最新版】沃德代驾源码全开源+前端uniapp

一.系统介绍 基于ThinkPHPUniapp开发的代驾软件。系统源码全开源&#xff0c;代驾软件的主要功能包括预约代驾、在线抢单、一键定位、在线支付、车主登记和代驾司机实名登记等‌。用户可以通过小程序预约代驾服务&#xff0c;系统会估算代驾价格并推送附近代驾司机供用户选择&…

react的 Fiber 节点的链表存储

在React Fiber架构中&#xff0c;Fiber节点的链表存储是一种重要的数据结构组织方式&#xff0c;用于管理和遍历Fiber节点。以下是关于Fiber节点链表存储的详细介绍&#xff1a; 链表结构 单链表&#xff1a;React Fiber节点通过next指针形成单链表结构。每个Fiber节点都有一…

Kafka + Kafka-UI

文章目录 前言&#x1f433; 一、使用纯 Kafka Kafka-UI &#xff08;无 Zookeeper&#xff09;Docker 配置&#x1f680; 启动步骤✅ 服务启动后地址&#x1f525; 注意事项&#xff08;使用 Kraft&#xff09;✅ NestJS Kafka 连接不变&#x1f9e0; 额外补充&#x1f4e6; …

AI声像融合守护幼儿安全——打骂/异常声音报警系统的智慧防护

幼儿园是孩子们快乐成长的摇篮&#xff0c;但打骂、哭闹或尖叫等异常事件可能打破这份宁静&#xff0c;威胁幼儿的身心安全。打骂/异常声音报警系统&#xff0c;依托尖端的AI声像融合技术&#xff0c;结合语音识别、情绪分析与视频行为检测&#xff0c;为幼儿园筑起一道智能安全…

Qt网络数据解析方法总结

在Qt中解析网络数据通常涉及接收原始字节流&#xff0c;并将其转换为有意义的应用层数据。以下是详细步骤和示例&#xff1a; 1. 网络数据接收 使用QTcpSocket或QUdpSocket接收数据&#xff0c;通过readyRead()信号触发读取&#xff1a; // 创建TCP Socket并连接信号 QTcpSo…

unity编辑器的json验证及格式化

UNITY编辑器的json格式化和验证工具资源-CSDN文库https://download.csdn.net/download/qq_38655924/90676188?spm1001.2014.3001.5501 反复去别的网站验证json太麻烦了 用这个工具能方便点 # Unity JSON工具 这是一个Unity编辑器扩展&#xff0c;用于验证、格式化和压缩JSO…

学习笔记:Qlib 量化投资平台框架 — FIRST STEPS

学习笔记&#xff1a;Qlib 量化投资平台框架 — FIRST STEPS Qlib 是微软亚洲研究院开源的一个面向人工智能的量化投资平台&#xff0c;旨在实现人工智能技术在量化投资中的潜力&#xff0c;赋能研究&#xff0c;并创造价值&#xff0c;从探索想法到实施生产。Qlib 支持多种机器…

操作系统:计算机世界的基石与演进

一、操作系统的本质与核心功能 操作系统如同计算机系统的"总管家"&#xff0c;在硬件与应用之间架起关键桥梁。从不同视角观察&#xff0c;其核心功能呈现多维价值&#xff1a; 硬件视角的双重使命&#xff1a; 硬件管理者&#xff1a;通过内存管理、进程调度和设…

基于单片机的温湿度采集系统(论文+源码)

2.1系统的功能 本系统的研制主要包括以下几项功能&#xff1a; (1)温度检测功能&#xff1a;对所处环境的温度进行检测&#xff1b; (2)湿度检测功能&#xff1a;对所处环境的湿度进行检测&#xff1b; (3)加热和制冷功能&#xff1a;可以完成加热和制冷功能。 (4)加湿和除…

webrtc使用

demo https://www.webrtc-experiment.com/ github开源demo https://github.com/muaz-khan/WebRTC-Experiment.git ws传递webrtc信令,本机不需要stun服务器,远端电脑需要ice服务器建立peer连接 const WebSocket = require(ws); const express =

【数据可视化-25】时尚零售销售数据集的机器学习可视化分析

🧑 博主简介:曾任某智慧城市类企业算法总监,目前在美国市场的物流公司从事高级算法工程师一职,深耕人工智能领域,精通python数据挖掘、可视化、机器学习等,发表过AI相关的专利并多次在AI类比赛中获奖。CSDN人工智能领域的优质创作者,提供AI相关的技术咨询、项目开发和个…

Python Cookbook-6.11 缓存环的实现

任务 你想定义一个固定尺寸的缓存&#xff0c;当它被填满时&#xff0c;新加入的元素会覆盖第一个(最老的)元素。这种数据结构在存储日志和历史信息时非常有用。 解决方案 当缓存填满时&#xff0c;本节解决方案及时地修改了缓存对象&#xff0c;使其从未填满的缓存类变成了…