【C++初阶】queue的常见操作和模拟实现以及deque的介绍

news2024/11/28 22:32:04

在这里插入图片描述

👦个人主页:@Weraphael
✍🏻作者简介:目前学习C++和算法
✈️专栏:C++航路
🐋 希望大家多多支持,咱一起进步!😁
如果文章对你有帮助的话
欢迎 评论💬 点赞👍🏻 收藏 📂 加关注✨


目录

  • 一、queue的基本概念
  • 二、 queue的常见操作
      • 2.1 构造函数
      • 2.2 empty
      • 2.3 size
      • 2.4 front
      • 2.5 back
      • 2.6 push
      • 2.7 pop
      • 2.8 赋值操作
  • 三、有关队列的力扣经典题
      • 3.1 二叉树的层序遍历
      • 3.2 用队列实现栈
  • 四、模拟实现queue
      • 4.1 简介
      • 4.2 代码实现
  • 五、deque(了解)
      • 5.1 deque的介绍
      • 5.2 deque的底层原理
      • 5.3 deque的缺陷
      • 5.4 为什么选择deque作为stack和queue的底层默认容器

一、queue的基本概念

  • queue是一种容器适配器,也是一种先进先出(First in First Out,简称FIFO)的数据结构, 其中从容器一端插入元素,另一端提取元素
  • 容器适配器通常会限制对底层容器的访问方式,因此不能遍历,但队列中只有

在这里插入图片描述

二、 queue的常见操作

2.1 构造函数

  • 默认构造
// T可以是任意类型
queue<T> q;
  • 拷贝构造
//q已知
queue<T> qq(q);

2.2 empty

功能:检测队列是否为空,是返回true,否则返回false

2.3 size

功能:返回队列中有效元素的个数

2.4 front

功能:返回队头元素

2.5 back

功能:返回队尾元素

2.6 push

功能:在队尾将元素val入队列

2.7 pop

功能:将队头元素出队列

2.8 赋值操作

#include <iostream>
#include <queue>
using namespace std;

int main()
{
	queue<int> q;
	// 插入
	q.push(10);
	q.push(20);
	q.push(30);
	q.push(40);


	queue<int> qq;
	//赋值运算符
	qq = q;

	cout << "元素个数:" << qq.size() << endl;
	cout << "队头元素" << qq.front() << endl;
	cout << "队尾元素" << qq.back() << endl;

	// 遍历
	while (!qq.empty())
	{
		cout << qq.front() << ' ';
		qq.pop();
	}
	cout << endl;
	return 0;
}

【输出结果】

在这里插入图片描述

三、有关队列的力扣经典题

3.1 二叉树的层序遍历

链接:点击跳转

【题目描述】

在这里插入图片描述

【思路】

在这里插入图片描述

【代码实现】

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) 
    {
        queue<TreeNode*>q;
        vector<vector<int>> vv;
        int levelSize;

        // 如果根节点不为空,则入队列
        if (root)
        {
            q.push(root);
            // 并且根节点的root一定为1
            levelSize = 1;
        }

        while (!q.empty())
        {
            // 一层一层出
            vector<int> v;
            for (int i = 0;i < levelSize;i++)
            {
                // 记录当前节点
                TreeNode* front = q.front();
                // 删除节点并存入
                q.pop();
                v.push_back(front->val);
                // 并带入它的子节点
                if (front->left) q.push(front->left);
                if (front->right) q.push(front->right);
            }
            vv.push_back(v);
            // 一层出完更新一层的个数
            levelSize = q.size();
        }
        return vv;
    }
};

3.2 用队列实现栈

链接:点击跳转

【题目描述】

在这里插入图片描述

【思路】

队列的特点是先进先出,而栈是先进后出,首先定义两个队列

在这里插入图片描述

那如何模拟一个栈呢?首先往空的队列入数据

在这里插入图片描述

对于栈来说,先出的是4。因此我们可以把1 2 3移到另一个空队列中

在这里插入图片描述

【代码实现】

class MyStack {
public:
    MyStack() {}
    
    void push(int x) 
    {
    	// 往不是空的队列插入数据
        if (in.empty())
        {
            out.push(x);
        }
        else
            in.push(x);
    }
    
    int pop() 
    {
    	// 保持一个队列为空
    	// 将一个为空的队列的前n-1个移到空队列
    	// 剩下的那个这是栈顶元素
        if (in.empty())
        {
            while (out.size() > 1)
            {
                int front = out.front();
                out.pop();
                in.push(front);
            }
            int ans = out.front();
            out.pop();
            return ans;
        }
        else // out为空
        {
            while (in.size() > 1)
            {
                int front = in.front();
                in.pop();
                out.push(front);
            }
            int ans = in.front();
            in.pop();
            return ans;
        }
    }
    
    int top() 
    {
        if (in.empty())
        {
           return out.back();
        }
        else 
        {
            return in.back();
        }
    }
    
    bool empty()
    {
        return in.empty() && out.empty();
    }
private:
    queue<int> in;
    queue<int> out;
};

四、模拟实现queue

4.1 简介

在这里插入图片描述

queue同样也是一种容器适配器,容器适配器可以被视为一种包装器,它们通过修改底层容器的接口或行为来实现新的功能。通过使用这些容器适配器,开发者可以方便地在不同场景下使用已有容器的功能,并且无需关心底层容器的具体实现。

其实就是STL中封装好的队列,在使用的时候我们不仅可以指定内部的数据类型,还可以指定内部的容器。不指定容器其实也是可以的,模板参数有一个缺省值,默认是deque

4.2 代码实现

#pragma once

namespace wj
{
	template<class T, class Container = deque<T>>
	class queue
	{
	public:
		void push(const T& x)        
		{
			_con.push_back(x);       
		}

		void pop()                   
		{
			_con.pop_front();    
		}

		const T& front()            
		{
			return _con.front();
		}

		const T& back()              
		{
			return _con.back();
		}

		size_t size()                
		{
			return _con.size();      
		}

		bool empty()                 
		{
			return _con.empty();     
		}

	private:
		Container _con;
	};

注意:队列就不能用vector适配了,因为vector没有提供pop_front接口,但是也可以强制适配。只需要改动pop接口

void pop()                   
{
	_con.erase(_con.begin());      
}

但注意,库里是没有强制适配的

在这里插入图片描述

为了贴近库,最好不要进行强制适配~

那么为什么库里不支持vector的头删呢?就是因为效率低,头删需要移动数据。

五、deque(了解)

5.1 deque的介绍

deque(双端队列):是一种可以在头尾两端进行插入和删除的"连续"空间的数据结构,且时间复杂度为O(1),它似乎是vectorlist的合体版。与vector比较,deque头插效率高,不需要搬移元素;与list比较,空间利用率比较高(是一块连续的空间)。

在这里插入图片描述

5.2 deque的底层原理

但如果深挖底层的话,deque并不是真正连续的空间,而是由一段段连续的小空间拼接而成的,实际deque类似于一个动态的二维数组,其底层结构如下图所示:

在这里插入图片描述

为了兼顾双端插入以及随机访问,deque的底层是使用一个中控数组(可以认为是指针数组)来管理一个个连续的空间,且第一个空间被开辟出来后是存放在中控数组的中央位置,之后不断插入数据,若一块连续空间已满只需要再开一块连续空间即可。也就是在中控数组中再增加一个指针。若是进行头插,则需要开辟一段新空间,将新的值存于连续空间的尾部。

5.3 deque的缺陷

  • vector比较,deque的优势是:头部插入和删除时,不需要搬移元素,效率特别高,而且在扩容时,也不需要搬移大量的元素,因此其效率是比vector高的。
  • list比较,deque底层是连续空间,空间利用率比较高,
  • 但是,deque有一个致命缺陷:不适合遍历,因为在遍历时,deque的迭代器要频繁的去检测其是否移动到
    某段小空间的边界,导致效率低下。大多数情况下优先考虑vectorlist。还有中部的插入删除操作相当复杂,若是直接在中部插入就要挪动当前空间的数据,更甚者还要牵扯到接下来的连续空间
  • deque的应用并不多,而目前能看到的一个应用就是,STL用其作为stackqueue的底层默认容器

5.4 为什么选择deque作为stack和queue的底层默认容器

在这里插入图片描述
在这里插入图片描述

  • stack是一种后进先出的特殊线性数据结构,因此只要具有push_back()pop_back()操作的线性结构,都可以作为stack的底层容器,比如vectorlist都可以;
  • queue是先进先出的特殊线性数据结构,只要具有push_backpop_front操作的线性结构,都可以作为queue的底层容器,比如list

但是STL中对stackqueue默认选择deque作为其底层容器,主要是因为:

  1. stackqueue不需要遍历(因此stackqueue没有迭代器),只需要在固定的一端或者两端进行操作。
  2. stack中元素增长时,dequevector的效率高(扩容时不需要搬移大量数据);queue中的元素增长
    时,deque不仅效率高,而且内存使用率高。结合了deque的优点,而完美的避开了其缺陷。

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

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

相关文章

相交链表:k神题解的一点小感慨

题目&#xff1a; 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null 。 图示两个链表在节点 c1 开始相交&#xff1a; 题目数据 保证 整个链式结构中不存在环。 朴素解法 用…

linux中busybox与文件系统的关系

busybox与文件系统 在 Linux 中&#xff0c;BusyBox 是一个精简的、多功能的工具集合&#xff0c;它包含了一系列常用的命令和实用程序&#xff0c;如 ls、cp、mkdir 等。BusyBox 的目标是提供一个功能完整而又占用空间较小的工具集合&#xff0c;适用于嵌入式系统或资源受限的…

Linux系统中驱动面试分享

​ 1、驱动程序分为几类&#xff1f; 字符设备驱动 块设备驱动 网络设备驱动 2、字符设备驱动需要实现的接口通常有哪些 open、close、read、write、ioctl等接口。 3、主设备号与次设备号的作用 主设备号和次设备号是用来标识系统中的设备的&#xff0c;主设备号用来标识…

信息熵 条件熵 交叉熵 联合熵 相对熵(KL散度) 互信息(信息增益)

粗略版快速总结 条件熵 H ( Q ∣ P ) 联合熵 H ( P , Q ) − H ( P ) 条件熵H(Q∣P)联合熵H(P,Q)−H(P) 条件熵H(Q∣P)联合熵H(P,Q)−H(P) 信息增益 I ( P , Q ) H ( P ) − H ( P ∣ Q ) H ( P ) H ( Q ) − H ( P , Q ) 信息增益 I(P,Q)H(P)−H(P∣Q)H(P)H(Q)-H(P,Q) 信息…

vulhub-tomcat弱口令

1.启动靶场 进入文件 进入目录 进入到靶场 启动靶场 docker-compose up -d 2.查看 ip地址 3.使用nmap对ip进行 扫描 发现存在8080的端口&#xff0c;并且端口是开放的状态&#xff0c;apache&#xff0c;tomcat搭建的 4.访问ip地址的端口 点击Manager app 6.开启BP进行抓包 随…

【力扣每日一题】2023.9.3 消灭怪物的最大数量

目录 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 代码&#xff1a; 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 题目比较长&#xff0c;我概括一下就是有一群怪物&#xff0c;每只怪物离城市的距离都不一样&#xff0c;并且靠近的速度也不一样&#x…

每日一题 1921. 消灭怪物的最大数量

难度&#xff1a;中等 思路&#xff1a; 已知速度和距离&#xff0c;可求时间必定先消灭时间最短的怪物求得时间数组排序&#xff0c;只要在第 i 秒时&#xff0c;time[i] > i &#xff0c;那么就可以消灭第 i 个怪物 代码&#xff1a; class Solution:def eliminateMax…

CVPR2022 Semi-Supervised Semantic Segmentation Using Unreliable Pseudo-Labels

Semi-Supervised Semantic Segmentation Using Unreliable Pseudo-Labels 使用不可靠的伪标签的半监督语义分割 Paper&#xff1a;https://openaccess.thecvf.com/content/CVPR2022/html/Wang_Semi-Supervised_Semantic_Segmentation_Using_Unreliable_Pseudo-Labels_CVPR_202…

vue+element-ui el-table组件二次封装实现虚拟滚动,解决数据量大渲染DOM过多而卡顿问题

一、此功能已集成到TTable组件中 二、最终效果 三、需求 某些页面不做分页时&#xff0c;当数据过多&#xff0c;会导致页面卡顿&#xff0c;甚至卡死 四、虚拟滚动 一、固定一个可视区域的大小并且其大小是不变的&#xff0c;那么要做到性能最大化就需要尽量少地渲染 DOM 元素…

一键导出文件名和位置,让你轻松管理文件!

想要轻松管理你的文件吗&#xff1f;试试我们的文件名和位置导出工具&#xff0c;一键导出文件名和位置&#xff0c;让你轻松管理你的文件&#xff01;我们的工具可以在不修改文件名的前提下&#xff0c;快速导出文件名和位置&#xff0c;让你随时随地查找和管理你的文件。 第…

C++算法 —— 动态规划(1)斐波那契数列模型

文章目录 1、动规思路简介2、第N个泰波那契数列3、三步问题4、使用最小花费爬楼梯5、解码方法6、动规分析总结 1、动规思路简介 动规的思路有五个步骤&#xff0c;且最好画图来理解细节&#xff0c;不要怕麻烦。当你开始画图&#xff0c;仔细阅读题时&#xff0c;学习中的沉浸…

绩效被打了 C 就要走人吗?

文章目录 前言一、什么是绩效&#xff1f;二、上级的评价是客观的吗&#xff1f;三、工作必须要和上级搞好关系吗&#xff1f;四、自我评价要写多少字&#xff1f;五、绩效低的话会被开除吗&#xff1f;六、低绩效钱会少吗?七、有关星球提问统一回复 前言 今天是英雄算法联盟九…

横向对比 npm、pnpm、tnpm、yarn 优缺点

前端工程化是现代Web开发中不可或缺的一环&#xff0c;它的出现极大地提升了前端开发的效率和质量。 在过去&#xff0c;前端开发依赖于手动管理文件和依赖&#xff0c;这导致了许多问题&#xff0c;如版本冲突、依赖混乱和构建繁琐等。而今&#xff0c;随着众多前端工程化工具…

荣耀10 关闭自动更新

1.电脑端下载安装手机助手 2.下载adb工具https://adbdownload.com/ 3.解压后&#xff0c;打开工具所在目录&#xff0c;在地址栏输入cmd然后回车 4.进入这黑麻麻的工具&#xff0c;输入adb devices然后回车&#xff0c;确认连接到手机 输入命令 adb shell pm disable-user com…

理解 std::thread::detach

C多线程并发编程入门&#xff08;目录&#xff09; detach 的作用 detach 的作用就是让线程独自执行。 为何需要 detach 在 理解 std::thread::join 中&#xff0c;我们看到了&#xff0c;如果所有线程都是一开始就在 main 函数中创建好的&#xff0c;那么只需要有一个 joi…

香橙派Orangepi Zero2 刷机步骤

目录 1.香橙派Orangepi Zero2简介 2.刷机 2.1物料准备 2.2 格式化SD卡 2.3 烧录镜像到SD卡 2.4 安装SD卡到Orangepi 2.5 连接Pi电源 2.6 MobaXterm 串口登陆Orangepi 2.6.1 连线示意图 2.6.2 MobaXterm 使用 2.6.3修改登陆密码 2.6.4 网络配置 2.7 SSH登陆开发版…

3D封装技术发展

长期以来&#xff0c;芯片制程微缩技术一直驱动着摩尔定律的延续。从1987年的1um制程到2015年的14nm制程&#xff0c;芯片制程迭代速度一直遵循摩尔定律的规律&#xff0c;即芯片上可以容纳的晶体管数目在大约每经过18个月到24个月便会增加一倍。但2015年以后&#xff0c;芯片制…

手把手教你申请腾讯云免费SSL证书

2023腾讯云免费SSL证书申请流程&#xff0c;一个腾讯云账号可以申请50张免费SSL证书&#xff0c;免费SSL证书为DV证书&#xff0c;仅支持单一域名&#xff0c;申请腾讯云免费SSL证书3分钟即可申请成功&#xff0c;免费SSL证书品牌为TrustAsia亚洲诚信&#xff0c;腾讯云百科分享…

[深度学习]大模型训练之框架篇--DeepSpeed使用

现在的模型越来越大&#xff0c;动辄几B甚至几百B。但是显卡显存大小根本无法支撑训练推理。例如&#xff0c;一块RTX2090的10G显存&#xff0c;光把模型加载上去&#xff0c;就会OOM&#xff0c;更别提后面的训练优化。 作为传统pytorch Dataparallel的一种替代&#xff0c;D…

技术干货 —— 手把手教你通过缓存提升 API 性能

许多开发者都希望能够彻底搞清楚 API 的工作方式&#xff0c;以及如何利用缓存 API 请求来提升业务&#xff0c;但是当这个需求进入实现阶段时&#xff0c;许多人就会发现手头并没有合适的工具和恰当的方法&#xff0c;所以我们今天就为大家做一个全面的讲解&#xff1a; ① 几…