「队列」实现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++)
概述 队列,是一种基本的数据结构,也是一种数据适配器。它在底层上以链表方法实现。 队列的显著特点是他的添加元素与删除元素操作:先加入的元素总是被先弹出。 一个队列应该应该是这样的: --------------QUEUE-------------——…...
C++ STL中 `set` 和 `multiset` 简单对比
在 C STL 中,set 和 multiset 都是用于存储唯一或重复元素的关联容器,但它们在处理元素的唯一性和特性方面有显著的区别。以下是这两个容器的详细比较: 1. 数据结构 set:基于红黑树(自平衡的二叉搜索树)实…...
代码随想录算法训练营Day20 | Leetcode 235 二叉搜索树的最近公共祖先 Leetcode 701 二叉搜索树中的插入操作
Leetcode 235 二叉搜索树的最近公共祖先 题目链接:235. 二叉搜索树的最近公共祖先 - 力扣(LeetCode) 代码随想录题解:代码随想录 (programmercarl.com) 思路:相比普通二叉树更简单,因为二叉搜索树的节点…...

第九届世界3D渲染大赛:赛程安排、赛事规则
第九届世界3D渲染大赛即将拉开帷幕,汇聚全球顶尖CG艺术家,展现最具有视觉盛宴的CG创作。那么该赛事的行程如何安排呢,赛事规则又是什么呢?本篇整理了赛事安排、赛事规则等内容,希望帮助大家。 赛事主题:Kin…...
RocketMQ5.0 Consumer Group
消费者分组的概念 消费者分组(Consumer Group)是指一组消费同一类消息的消费者实例。每个消费者分组有一个唯一的名称,用于标识该分组。消费者分组的设计使得消息能够被多个消费者实例并行消费,同时确保每条消息只被一个消费者实例…...

vulnhub之serial
这次我们来做这个靶场 项目地址https://download.vulnhub.com/serial/serial.zip 使用vm新建虚拟机 以下为注意事项 第一步,收集资产 扫描靶场ip netdiscover -i eth0 -r 192.168.177.0/24 抓个包 扫描目录 看到了cookie中有一个user Tzo0OiJVc2VyIjoyOntzOj…...
卷积神经网络(CNN)简单原理与简单代码实现
卷积神经网络(CNN)简单原理与简单代码实现 卷积神经网络(CNN)简单原理基本原理卷积层(Convolutional Layer):激活层(Activation Layer):池化层(Po…...

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

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

新160个crackme - 022-CM_2
运行分析 需破解Name和Serial,输入的小写字母都会变为大写字母 PE分析 C程序,32位,无壳 静态分析&动态调试 发现关键字符串 ida动态调试,发现Name和Serial长度需要大于5,且Serial前6位明文爆出,6287-A …...
在.c和.h 文件里定义数组的区别
在C语言开发中,掌握如何在.c文件和.h文件中合理定义数组,对于维护代码的模块化和避免不必要的编译错误至关重要。本文将探讨在这两种类型的文件中定义数组时需要注意的几个关键方面,包括定义性质、作用域、重复定义问题以及外部可见性等&…...

使用Step Functions运行AWS Backup时必备的权限要点
引言 在尝试从Step Functions执行AWS Backup的按需备份时,我在权限方面遇到了一些困难。为了备忘,我将这些经验写成这篇文章。 概述 从Step Functions执行AWS Backup时,需要分配以下权限: 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电脑玩的休闲游戏推荐
对于游戏爱好者而言,Mac似乎并不是游戏体验的首选平台。这主要是因为相较于Windows系统,Mac上的游戏资源显得相对有限。不过,这并不意味着Mac用户就与游戏世界绝缘。实际上,Mac平台上有着一系列小巧精致且趣味横生的小游戏&#x…...

浅谈KMP算法(c++)
目录 前缀函数应用【模板】KMP题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 提示样例 1 解释数据规模与约定 思路AC代码 本质不同子串数 例题讲解[NOI2014] 动物园题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 提示思路AC代码 [POI2006] OKR-Periods of …...
关于C++编程注意点(竞赛)
赛前准备 多复习 重中之重, 多刷题 确保手感 参加几场模拟赛,熟悉流程 熟悉 Linux 系统,否则你将会手忙脚乱 放松心情,调整心态,分数 实力 心态 赛中注意 输入输出方面 在数据范围超过 时尽量使用 scanf pr…...

Markdown文本编辑器:Typora for Mac/win 中文版
Markdown 是一种轻量级的标记语言,它允许用户使用易读易写的纯文本格式编写文档。Typora 支持且仅支持 Markdown 语法的文本编辑,生成的文档后缀名为 .md。 这款软件的特点包括: 实时预览: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. 窗口函数基础用法:OVER关键字4.1 语法4.2 场景一 :计算每个值和整体平均值的差值4.2.1 需求4.2…...
Python3 爬虫 数据抓包
一、数据抓包 所谓抓包(Package Capture),简单来说,就是在网络数据传输的过程中对数据包进行截获、查看、修改或转发的过程。如果把网络上发送与接收的数据包理解为快递包裹,那么在快递运输的过程中查看里面的内容&…...

网络六边形受到攻击
大家读完觉得有帮助记得关注和点赞!!! 抽象 现代智能交通系统 (ITS) 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 (…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...
SkyWalking 10.2.0 SWCK 配置过程
SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外,K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案,全安装在K8S群集中。 具体可参…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战
在现代战争中,电磁频谱已成为继陆、海、空、天之后的 “第五维战场”,雷达作为电磁频谱领域的关键装备,其干扰与抗干扰能力的较量,直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器,凭借数字射…...

select、poll、epoll 与 Reactor 模式
在高并发网络编程领域,高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表,以及基于它们实现的 Reactor 模式,为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。 一、I…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...

html-<abbr> 缩写或首字母缩略词
定义与作用 <abbr> 标签用于表示缩写或首字母缩略词,它可以帮助用户更好地理解缩写的含义,尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时,会显示一个提示框。 示例&#x…...
JS手写代码篇----使用Promise封装AJAX请求
15、使用Promise封装AJAX请求 promise就有reject和resolve了,就不必写成功和失败的回调函数了 const BASEURL ./手写ajax/test.jsonfunction promiseAjax() {return new Promise((resolve, reject) > {const xhr new XMLHttpRequest();xhr.open("get&quo…...