当前位置: 首页 > news >正文

「队列」实现FIFO队列(先进先出队列|queue)的功能 / 手撕数据结构(C++)

概述

队列,是一种基本的数据结构,也是一种数据适配器。它在底层上以链表方法实现。

队列的显著特点是他的添加元素与删除元素操作:先加入的元素总是被先弹出。

一个队列应该应该是这样的:

          --------------QUEUE-------------————     ————     ————     ————
pop() ←--  T1  ←--  T2  ←--  T3  ←--  T4  ←-- push()————     ————     ————     ————     --------------------------------front()                     back()*注意*-------------------------------→队列的内部是一张由front指向back的链表

Tn代表该元素被加入到队列的次序。

一个队列有以下四种基本行为:

front()表示对队列头元素的访问操作。如得到元素T1。

pop()表示对队列头元素的弹出操作。我们弹出T1

               ---------QUEUE---------————     ————     ————pop() ←--  T2  ←--  T3  ←--  T4  ←-- push()————     ————     ————     -----------------------front()           back()

现在T2成为队头元素。 

back()表示对队列尾元素的访问操作。如当前会得到T4。

push()表示对队列尾部压入新元素。我们压入T5

          --------------QUEUE-------------————     ————     ————     ————
pop() ←--  T2  ←--  T3  ←--  T4  ←--  T5  ←-- push()————     ————     ————     ————     --------------------------------front()                     back()

现在T5成为尾元素。 

接下来我们通过封装queue类,实现队列的一些基本功能 。(Code和测试案例附后)

命名空间

C++有自己的std命名空间下的queue,为了进行区分,封装一个自己的动态数组命名空间custom_queue。

使用namespace关键字封装,使用时可以声明using namespace custom_queu;在作用域内声明,或custom_queue::局部声明。

namespace custom_queue{...
}//作用域内声明
using namespace custom_queue;//局部声明
custom_queue::...

成员变量

template <typename T>泛型,作为数据适配器,他的数据单位应该是任意一种类型,此时暂用T表示,至于T为何物将在实例化时以<>告知。

定义class类queue,封装三个成员变量:queue_node<T>* val_front; queue_node<T>* val_back; size_t val_size;

(size_t 是C/C++标准在stddef.h中定义的(这个头文件通常不需要#include),size_t 类型专门用于表示长度,它是无符号整数。)

我们还要额外定义嵌套类queue_node,它只能被queue类使用,这就实现了结构功能的封装。

queue_node<T>* val_front是队头处的指针。

queue_node<T>* val_back是队尾处的指针。

size_t val_size用于记录当前队列的长度


template<typename T>
class queue {
private:template<typename T>class queue_node {private:...};queue_node<T>* val_front;queue_node<T>* val_back;size_t val_size;
public:...
}

定义class类queue_node,封装两个成员变量:T val; queue_node*next

声明友员类friend class queu(queue为模版类,模版友员类前加泛型声明),这使得queue可以操控queue_node的私有成员,将queue_node的构造函数和析构函数定为私有,这样就只用queue能管理queue_node了。

T val当前节点值。

queue_node*next指向下一个节点

另有构造函数接受一个T elem,创建新节点。

析构函数无须函数体,完全由trie类代管,略去不表。

禁用拷贝构造和重载等于号:默认拷贝构造和等于号进行,指针变量赋值,这存在极大问题(两指针争抢堆上的数据同一块数据),另有深层拷贝解决,略去不表。

template<typename T>
class queue_node {
private:template<typename T>friend class queue;T val;queue_node* next;queue_node(T elem) :val(elem), next(nullptr) {};~queue_node(){};queue_node(const queue_node& another)=delete;queue_node& operator=(const queue_node& another) = delete;
};

创建销毁

提供四种构造。

无参构造:创建空队列。

复制构造:用另一个队列进行深度拷贝。所谓深度拷贝就是以another指针指向的值作为参数创建新指针而不是让两指针指向同一值。让队头获得创新得到的第一个节点,然后以两个临时指针another_val与this_val进行同步,this_val时时构造与another_val指向的值相同的新节点。

最后队尾获得创建得到的最后一个节点。

析构函数:当队列非空,循环进行头结点弹出。后面实现判断空队列行为和弹出行为。

另有重载等于号:作用于复制构造相同。

queue() :val_front(nullptr), val_back(nullptr), val_size(0) {};
queue(const queue& another) :queue() {int len = another.val_size;val_size = len;if (len) {queue_node<T>* this_val=new queue_node<T>(another.val_front->val);const queue_node<T>* another_val = another.val_front->next;val_front = this_val;while (--len) {this_val->next= new queue_node<T>(another_val->val);this_val = this_val->next;another_val = another_val->next;}val_back = this_val;}
}
~queue() {while (!empty())pop();
}
queue& operator=(const queue& another){val_front = val_back = nullptr;int len = another.val_size;val_size = len;if (len) {queue_node<T>* this_val = new queue_node<T>(another.val_front->val);const queue_node<T>* another_val = another.val_front->next;val_front = this_val;while (--len) {this_val->next = new queue_node<T>(another_val->val);this_val = this_val->next;another_val = another_val->next;}val_back = this_val;}return *this;
}

数据控制

获取长度:返回val_size。

判断为空:返回val_size ? false : true。

队尾压入:如果是空队列,队头申请新节点node后,令队尾等于队头。否则在队尾后面申请新节点。

队头弹出:如果是空队列,抛出异常。否则获取当前头结点的next,删除头节点后将next作为头结点。如果队列大小为1,那么删除后应将头尾全部置为nullptr空节点。

size_t size() {return val_size;
}
bool empty() {return val_size ? false : true;
}
void push(const T elem) {if (val_size == 0) {val_front = new queue_node<T>(elem);val_back = val_front;}else {val_back->next = new queue_node<T>(elem);val_back = val_back->next;}val_size++;
}
void pop(){assert(val_size > 0);queue_node<T>* temp = val_front->next;delete val_front;val_front = temp;val_size--;if (!val_size)val_front = val_back= nullptr;
}

数据访问

访问队头:判断无异常后返回队头的常量引用。

访问队尾:判断无异常后返回队尾的常量引用。

我们的queue访问操作不支持接受方进行数据更改。

const T& front() {assert(val_size > 0);return (val_front->val);
}
const T& back() {assert(val_size > 0);return (val_back->val);
}

Code

#pragma once
#include <cassert>
namespace custom_queue {template<typename T>class queue {private:template<typename T>class queue_node {private:template<typename T>friend class queue;T val;queue_node* next;queue_node(T elem) :val(elem), next(nullptr) {};~queue_node(){};queue_node(const queue_node& another)=delete;queue_node& operator=(const queue_node& another) = delete;};queue_node<T>* val_front;queue_node<T>* val_back;size_t val_size;public:queue() :val_front(nullptr), val_back(nullptr), val_size(0) {};queue(const queue& another) :queue() {int len = another.val_size;val_size = len;if (len) {queue_node<T>* this_val=new queue_node<T>(another.val_front->val);const queue_node<T>* another_val = another.val_front->next;val_front = this_val;while (--len) {this_val->next= new queue_node<T>(another_val->val);this_val = this_val->next;another_val = another_val->next;}val_back = this_val;}}~queue() {while (!empty())pop();}queue& operator=(const queue& another){val_front = val_back = nullptr;int len = another.val_size;val_size = len;if (len) {queue_node<T>* this_val = new queue_node<T>(another.val_front->val);const queue_node<T>* another_val = another.val_front->next;val_front = this_val;while (--len) {this_val->next = new queue_node<T>(another_val->val);this_val = this_val->next;another_val = another_val->next;}val_back = this_val;}return *this;}int size() {return val_size;}bool empty() {return val_size ? false : true;}void push(const T elem) {if (val_size == 0) {val_front = new queue_node<T>(elem);val_back = val_front;}else {val_back->next = new queue_node<T>(elem);val_back = val_back->next;}val_size++;}void pop(){assert(val_size > 0);queue_node<T>* temp = val_front->next;delete val_front;val_front = temp;val_size--;if (!val_size)val_front = val_back= nullptr;}const T& front() {assert(val_size > 0);return (val_front->val);}const T& back() {assert(val_size > 0);return (val_back->val);}};
}

测试

#include <iostream>
#include "queue.h"
using namespace std;
int main()
{custom_queue::queue<char>que1;que1.push('a'); que1.push('b'); que1.push('c');custom_queue::queue<char>que2(que1);while (!que1.empty()) {cout << que1.front();que1.pop();}cout << endl;while (!que2.empty()) {cout << que2.front();que2.pop();}cout << endl;que2.push('x');cout <<que2.front()<<' '<< que2.back();cout << endl;return 0;
}

 

相关文章:

「队列」实现FIFO队列(先进先出队列|queue)的功能 / 手撕数据结构(C++)

概述 队列&#xff0c;是一种基本的数据结构&#xff0c;也是一种数据适配器。它在底层上以链表方法实现。 队列的显著特点是他的添加元素与删除元素操作&#xff1a;先加入的元素总是被先弹出。 一个队列应该应该是这样的&#xff1a; --------------QUEUE-------------——…...

C++ STL中 `set` 和 `multiset` 简单对比

在 C STL 中&#xff0c;set 和 multiset 都是用于存储唯一或重复元素的关联容器&#xff0c;但它们在处理元素的唯一性和特性方面有显著的区别。以下是这两个容器的详细比较&#xff1a; 1. 数据结构 set&#xff1a;基于红黑树&#xff08;自平衡的二叉搜索树&#xff09;实…...

代码随想录算法训练营Day20 | Leetcode 235 二叉搜索树的最近公共祖先 Leetcode 701 二叉搜索树中的插入操作

Leetcode 235 二叉搜索树的最近公共祖先 题目链接&#xff1a;235. 二叉搜索树的最近公共祖先 - 力扣&#xff08;LeetCode&#xff09; 代码随想录题解&#xff1a;代码随想录 (programmercarl.com) 思路&#xff1a;相比普通二叉树更简单&#xff0c;因为二叉搜索树的节点…...

第九届世界3D渲染大赛:赛程安排、赛事规则

第九届世界3D渲染大赛即将拉开帷幕&#xff0c;汇聚全球顶尖CG艺术家&#xff0c;展现最具有视觉盛宴的CG创作。那么该赛事的行程如何安排呢&#xff0c;赛事规则又是什么呢&#xff1f;本篇整理了赛事安排、赛事规则等内容&#xff0c;希望帮助大家。 赛事主题&#xff1a;Kin…...

RocketMQ5.0 Consumer Group

消费者分组的概念 消费者分组&#xff08;Consumer Group&#xff09;是指一组消费同一类消息的消费者实例。每个消费者分组有一个唯一的名称&#xff0c;用于标识该分组。消费者分组的设计使得消息能够被多个消费者实例并行消费&#xff0c;同时确保每条消息只被一个消费者实例…...

vulnhub之serial

这次我们来做这个靶场 项目地址https://download.vulnhub.com/serial/serial.zip 使用vm新建虚拟机 以下为注意事项 第一步&#xff0c;收集资产 扫描靶场ip netdiscover -i eth0 -r 192.168.177.0/24 抓个包 扫描目录 看到了cookie中有一个user Tzo0OiJVc2VyIjoyOntzOj…...

卷积神经网络(CNN)简单原理与简单代码实现

卷积神经网络&#xff08;CNN&#xff09;简单原理与简单代码实现 卷积神经网络&#xff08;CNN&#xff09;简单原理基本原理卷积层&#xff08;Convolutional Layer&#xff09;&#xff1a;激活层&#xff08;Activation Layer&#xff09;&#xff1a;池化层&#xff08;Po…...

实时数仓分层架构详解

首先&#xff0c;我们从数据仓库说起。 数据仓库的概念可以追溯到20世纪80年代&#xff0c;当时IBM的研究人员提出了商业数据仓库的概念。数据仓库概念的提出&#xff0c;是为了解决和数据流相关的各种问题&#xff0c;特别是多重数据复制带来的高成本问题。 数据仓库之父Bill …...

计算机“八股文”在实际工作中是助力、阻力还是空谈?

“八股文”在实际工作中是助力、阻力还是空谈&#xff1f; 作为现在各类大中小企业面试程序员时的必问内容&#xff0c;“八股文”似乎是很重要的存在。但“八股文”是否能在实际工作中发挥它“敲门砖”应有的作用呢&#xff1f;有IT人士不禁发出疑问&#xff1a;程序员面试考…...

新160个crackme - 022-CM_2

运行分析 需破解Name和Serial&#xff0c;输入的小写字母都会变为大写字母 PE分析 C程序&#xff0c;32位&#xff0c;无壳 静态分析&动态调试 发现关键字符串 ida动态调试&#xff0c;发现Name和Serial长度需要大于5&#xff0c;且Serial前6位明文爆出&#xff0c;6287-A …...

在.c和.h 文件里定义数组的区别

在C语言开发中&#xff0c;掌握如何在.c文件和.h文件中合理定义数组&#xff0c;对于维护代码的模块化和避免不必要的编译错误至关重要。本文将探讨在这两种类型的文件中定义数组时需要注意的几个关键方面&#xff0c;包括定义性质、作用域、重复定义问题以及外部可见性等&…...

使用Step Functions运行AWS Backup时必备的权限要点

引言 在尝试从Step Functions执行AWS Backup的按需备份时&#xff0c;我在权限方面遇到了一些困难。为了备忘&#xff0c;我将这些经验写成这篇文章。 概述 从Step Functions执行AWS Backup时&#xff0c;需要分配以下权限&#xff1a; AWS Backup相关权限 执行备份的权限…...

强化JS基础水平的10个单行代码来喽!(必看)

目录 生成数组 数组简单数据去重 多数组取交集 重新加载当前页面 滚动到页面顶部 查找最大值索引 进制转换 文本粘贴 删除无效属性 随机颜色生成 生成数组 当你需要要生成一个0-99的数组 // 生成一个0-99的数组 // 方案一 const createArr n > Array.from(new A…...

大模型学习笔记 - 大纲

LLM 大纲 LLM 大纲 1. LLM 模型架构 LLM 技术细节 - 注意力机制LLM 技术细节 - 位置编码 2. LLM 预训练3. LLM 指令微调 LLM 高效微调技术 4. LLM 人类对齐 LLM InstructGPTLLM PPO算法LLM DPO 算法 5. LLM 解码与部署6. LLM 模型LLaMA 系列7. LLM RAG 1. LLM 模型架构 大模…...

苹果电脑可以玩什么小游戏 适合Mac电脑玩的休闲游戏推荐

对于游戏爱好者而言&#xff0c;Mac似乎并不是游戏体验的首选平台。这主要是因为相较于Windows系统&#xff0c;Mac上的游戏资源显得相对有限。不过&#xff0c;这并不意味着Mac用户就与游戏世界绝缘。实际上&#xff0c;Mac平台上有着一系列小巧精致且趣味横生的小游戏&#x…...

浅谈KMP算法(c++)

目录 前缀函数应用【模板】KMP题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 提示样例 1 解释数据规模与约定 思路AC代码 本质不同子串数 例题讲解[NOI2014] 动物园题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 提示思路AC代码 [POI2006] OKR-Periods of …...

关于C++编程注意点(竞赛)

赛前准备 多复习 重中之重&#xff0c; 多刷题 确保手感 参加几场模拟赛&#xff0c;熟悉流程 熟悉 Linux 系统&#xff0c;否则你将会手忙脚乱 放松心情&#xff0c;调整心态&#xff0c;分数 实力 心态 赛中注意 输入输出方面 在数据范围超过 时尽量使用 scanf pr…...

Markdown文本编辑器:Typora for Mac/win 中文版

Markdown 是一种轻量级的标记语言&#xff0c;它允许用户使用易读易写的纯文本格式编写文档。Typora 支持且仅支持 Markdown 语法的文本编辑&#xff0c;生成的文档后缀名为 .md。 这款软件的特点包括&#xff1a; 实时预览&#xff1a;Typora 的一个显著特点是实时预览&#x…...

Mysql-窗口函数一

文章目录 1. 窗口函数概述1.1 介绍1.2 作用 2. 场景说明2.1 准备工作2.2 场景说明2.3 分析2.4 实现2.4.1 非窗口函数方式实现2.4.2 窗口函数方式实现 3. 窗口函数分类4. 窗口函数基础用法&#xff1a;OVER关键字4.1 语法4.2 场景一 :计算每个值和整体平均值的差值4.2.1 需求4.2…...

Python3 爬虫 数据抓包

一、数据抓包 所谓抓包&#xff08;Package Capture&#xff09;&#xff0c;简单来说&#xff0c;就是在网络数据传输的过程中对数据包进行截获、查看、修改或转发的过程。如果把网络上发送与接收的数据包理解为快递包裹&#xff0c;那么在快递运输的过程中查看里面的内容&…...

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...

19c补丁后oracle属主变化,导致不能识别磁盘组

补丁后服务器重启&#xff0c;数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后&#xff0c;存在与用户组权限相关的问题。具体表现为&#xff0c;Oracle 实例的运行用户&#xff08;oracle&#xff09;和集…...

模型参数、模型存储精度、参数与显存

模型参数量衡量单位 M&#xff1a;百万&#xff08;Million&#xff09; B&#xff1a;十亿&#xff08;Billion&#xff09; 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的&#xff0c;但是一个参数所表示多少字节不一定&#xff0c;需要看这个参数以什么…...

CentOS下的分布式内存计算Spark环境部署

一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架&#xff0c;相比 MapReduce 具有以下核心优势&#xff1a; 内存计算&#xff1a;数据可常驻内存&#xff0c;迭代计算性能提升 10-100 倍&#xff08;文档段落&#xff1a;3-79…...

定时器任务——若依源码分析

分析util包下面的工具类schedule utils&#xff1a; ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类&#xff0c;封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz&#xff0c;先构建任务的 JobD…...

Map相关知识

数据结构 二叉树 二叉树&#xff0c;顾名思义&#xff0c;每个节点最多有两个“叉”&#xff0c;也就是两个子节点&#xff0c;分别是左子 节点和右子节点。不过&#xff0c;二叉树并不要求每个节点都有两个子节点&#xff0c;有的节点只 有左子节点&#xff0c;有的节点只有…...

CMake控制VS2022项目文件分组

我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

#Uniapp篇:chrome调试unapp适配

chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器&#xff1a;Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...

Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析

Java求职者面试指南&#xff1a;Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问&#xff08;基础概念问题&#xff09; 1. 请解释Spring框架的核心容器是什么&#xff1f;它在Spring中起到什么作用&#xff1f; Spring框架的核心容器是IoC容器&#…...

免费PDF转图片工具

免费PDF转图片工具 一款简单易用的PDF转图片工具&#xff0c;可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件&#xff0c;也不需要在线上传文件&#xff0c;保护您的隐私。 工具截图 主要特点 &#x1f680; 快速转换&#xff1a;本地转换&#xff0c;无需等待上…...