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

news2024/11/15 10:51:06

概述

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

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

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

          --------------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;
}

 

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

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

相关文章

大数据资源平台建设可行性研究方案(58页PPT)

方案介绍: 在当今信息化高速发展的时代&#xff0c;大数据已成为推动各行各业创新与转型的关键力量。为了充分利用大数据的潜在价值&#xff0c;构建一个高效、安全、可扩展的大数据资源平台显得尤为重要。通过本方案的实施企业可以显著提升数据处理能力、优化资源配置、促进业…

SQL注入实例(sqli-labs/less-8)

0、初始页面 1、确定闭合字符 ?id1 and 11 ?id1 and 12 ?id1 ?id1 and 11 -- ?id1 and 12 -- 确定闭合字符为单引号&#xff0c;并且正确页面与错误页面的显示不同 2、爆库名 使用python脚本 def inject_database1(url):name for i in range(1, 20):low 32high 1…

【大模型从入门到精通5】openAI API高级内容审核-1

这里写目录标题 高级内容审核利用 OpenAI 内容审核 API 的高级内容审核技术整合与实施使用自定义规则增强审核综合示例防止提示注入的策略使用分隔符隔离命令理解分隔符使用分隔符实现命令隔离 高级内容审核 利用 OpenAI 内容审核 API 的高级内容审核技术 OpenAI 内容审核 AP…

SQL注入漏洞复现1

一、靶场信息 sqli-labs下载&#xff1a;https://github.com/Audi-1/sqli-labs phpstudy下载地址&#xff1a;http://down.php.cn/PhpStudy20180211.zip 我是在本地安装小皮搭建环境&#xff0c;相比于在服务器上搭建环境&#xff0c;更加简单 二、注入实操 Less-1 爆库名…

搭建高可用OpenStack(Queen版)集群(三)之部署认证管理服务(Keystone)控制节点集群

一、搭建高可用OpenStack&#xff08;Queen版&#xff09;集群之部署认证服务&#xff08;Keystone&#xff09;控制节点集群 一、Identity 服务简介 1、Identity概述 Identity为认证管理&#xff0c;授权管理和服务目录服务管理提供单点整合。其它Openstack服务将身份认证服务…

常用的图像增强操作

我们将介绍如何用PIL库实现一些简单的图像增强方法。 [!NOTE] 初始化配置 import numpy as np from PIL import Image, ImageOps, ImageEnhance import warningswarnings.filterwarnings(ignore) IMAGE_SIZE 640[!important] 辅助函数 主要用于控制增强幅度 def int_param…

centos7.9升级rocky

ELevate Quickstart Guide | AlmaLinux Wiki 将 CentOS 7 升级到 AlmaLinux 9 由于 Leapp 工具设计为执行一步升级&#xff0c;为了将您的 CentOS 7 机器升级到 AlmaLinux 9&#xff0c;您需要拆分升级过程&#xff1a; CentOS 7 到 AlmaLinux 8AlmaLinux 8 到 AlmaLinux 9 …

Chainlit快速实现AI对话应用1 分钟内实现聊天数据的持久化保存

概述 默认情况下&#xff0c;Chainlit 应用不会保留其生成的聊天和元素。即网页一刷新&#xff0c;所有的聊天记录&#xff0c;页面上的所有聊天记录都会消失。但是&#xff0c;存储和利用这些数据的能力可能是您的项目或组织的重要组成部分。 一旦启用&#xff0c;数据持久性…

3d模型贴图后有部分阴影怎么解决?---模大狮模型网

在展览3D模型设计行业中&#xff0c;贴图是使展品栩栩如生的关键步骤之一。然而&#xff0c;有时在贴图后可能会出现一些意外的阴影&#xff0c;影响了展品的逼真度和视觉效果。本文将探讨在3D模型贴图后出现部分阴影的原因及解决方法&#xff0c;帮助设计师有效应对这一常见问…

Transwarp Data Studio 4.0 :适应AI新时代实现三大能力提升

企业数据资产管理能力建设需要经历资源化、资产化和资本化三个阶段&#xff0c;对应数据底座建设、资产管理平台建设、流通运营平台建设三大任务。星环科技大数据开发工具 Transwarp Data Studio&#xff0c;在此过程中发挥着承上启下的关键作用。近日&#xff0c;星环科技重磅…

ESP8266 烧录----待坑

虚焊&#xff0c;连接不稳定&#xff08;*******&#xff09;&#xff1b;暂时只有通过测试接口电压进行判断&#xff0c;无其它方法 问题总结 1. 输入电压为3.3V USB转TTL RX TX 必须不能高3.3否则无输出(USB转TTL有多种类型&#xff0c;测RX TX电源&#xff1b;天问的是5V的…

sqli-labs闯关1-4

第一关&#xff1a; 这里的输入了 &#xff1f;id1 意思是以GET方式传入id1的参数 就等于SELECT * FROM users WHERE id1 LIMIT 0,1 注意&#xff1a;-- 与-- 空格的区别 在url中输入了--以后&#xff0c;后端数据会变成--空格。在 url中输入 -- 空格 变成 -- 在mysql中&…

fieldIndex on a Row without schema is undefined

Bug信息 Caused by: java.lang.UnsupportedOperationException: fieldIndex on a Row without schema is undefined.at org.apache.spark.sql.Row$class.fieldIndex(Row.scala:342)at org.apache.spark.sql.catalyst.expressions.GenericRow.fieldIndex(rows.scala:166)at org…

Java - 2.1 Java基础

2.1 Java基础 &#xff08;1&#xff09;JVM & JRE & JDK JVM &#xff08;Java Virtual Machine&#xff09;是 Java 虚拟机&#xff0c;它的作用是运行 Java 字节码文件&#xff0c;它有针对不同系统的不同实现&#xff0c;以此达成一次编译&#xff0c;随处运行的…

【限免】通信信号与干扰信号【附MATLAB代码】

微信公众号&#xff1a;EW Frontier 关注可了解更多的雷达、通信、人工智能相关代码。问题或建议&#xff0c;请公众号留言; 个人博客&#xff1a;106.54.201.174 QQ交流群&#xff1a;949444104 摘要 本项目主要模拟仿真常见通信信号及干扰信号&#xff0c;高斯白噪声、噪声调…

ARMxy工控机使用Node-Red教程:实现Modbus转MQTT协议二次开发(8)

Modbus/TCP与MQTT通信案例 7.1 案例说明 案例功能&#xff1a;使用node-red工具通过Modbus/RTU协议采集M160T IO模块数据&#xff0c;再经过MQTT协议的转换上传到上位机Ubuntu。基于 node-red 部署程序&#xff0c;实现获取 M160T IO 模块数据上传到上位机。 图 98 7.2 案例…

TeleVis:基于NLP的新冠新闻舆情可视化项目

关联比赛: 疫情数据可视化公益行动 一、项目名称 TeleVis&#xff1a;基于NLP的新冠新闻舆情可视化项目 二、团队信息 团队名称&#xff1a;TeleVis 单 位&#xff1a;金融壹账通大数据研究院 成 员&#xff1a;杨镭、郭凌峰、王天宇、黄北辰、齐婧含 三、项目介绍 政企机构的…

AST 基础

目录 AST 的基本结构安装 babel 库babel 中的组件parse 与 generatorparsegenerator完整代码 traverse 与 visitortraversevisitor 的定义方式path 对象中的 traverse types判断节点类型生成新的节点valueToNode&#xff08;方便的生成字面量&#xff09; path 对象(重点)path …

C++——多态经典案例(三)计算器

案例&#xff1a;使用多态实现一个简单的计算器&#xff0c;计算两个数的加减乘除结果 分析&#xff1a;定义一个抽象类AbstractCalc &#xff0c;其内部定义一个纯虚函数getResult&#xff0c;用于得到计算结果 定义加减乘除四个类&#xff0c;分别继承这个抽象类AbstractCal…