js实现队列

news2024/11/25 16:32:40

目录

  • 一、什么是JavaScript队列数据结构
  • 二、创建一个JavaScript队列数据结构
  • 三、封装队列方法
    • ①向队列添加元素
    • ②检查队列是否为空
    • ③获取队列的长度
    • ④从队列移除元素
    • ⑤查看队列头元素
    • ⑥清空队列
    • ⑦创建toString方法
  • 四、使用Queue类

一、什么是JavaScript队列数据结构

在上一篇文章中,我们了解并学习了JavaScript栈数据结构,本章开始JavaScript的队列数据结,第一章先认识队列与怎么去封装一个队列。

前面的文章里我们已经学习了栈。队列和栈非常类似,但是使用了与后进先出不同的原则。本章学习这些内容。
在这里插入图片描述

队列是遵循先进先出(FIFO,也称为先来先服务)原则的一组有序的项。队列在尾部添加新元素,并从顶部移除元素。最新添加的元素必须排在队列的末尾

在现实中,最常见的队列的例子就是排队,例如在火车站的售票处、超时里的收银台等,我们都会排队,排在第一位的人会先接受服务。

在计算机科学中,一个常见的例子就是打印队列。比如说我们需要打印五份文档。我们会打开每个文档,然后点击打印按钮,每个文档都会被发送至打印队列。第一个发送到打印队列的文档会首先被打印,以此类推,直到打印完所有文档。

二、创建一个JavaScript队列数据结构

我们需要创建自己的类来表示一个队列。先从最基本的声明类开始。

class Queue {
	constructor(){
		this.count = 0;	//{1}
		this.lowestCount = 0;	//{2}
		this.items = {};	//{3}
	}
}

首先需要一个用于存储队列中元素的数据结构。我们可以使用数组,就像上一章的Stack类那样。

但是,为了写出一个在获取元素时更高效的数据结构,我们将使用一个对象来存储我们的元素(行{3})。

你会发现Queue类和Stack类非常类似,只是添加和移除元素的原则不同。

也可以声明一个count属性来帮助我们控制队列的大小(行{1})。

此外,由于我们将要从队列前端移除元素,同样需要一个变量来帮助我们追踪第一个元素。因此,声明一个lowestCount变量(行{2})。

接下来需要声明一些队列可用的方法:

  • enqueue(element(s)):向队列尾部添加一个(或多个)新的项。
  • isEmpty():如果队列中不包含任何元素,返回true,否则返回false。
  • size():返回队列包含的元素个数,与数组的length属性类似。
  • dequeue():移除队列的第一项(即排在队列最前面的项)并返回被移除的元素。
  • peek():返回队列中第一个元素——最先被添加,也将是最先被移除的元素。队列不做任何变动(不移除元素,只返回元素信息——与Stack类的peek方法非常类似)。该方法在其他语言中也可以叫作front 方法。
  • clear():清空整个队列。
  • toString():将队列转为字符串返回。
    下一小节来封装并实现这些方法。

三、封装队列方法

①向队列添加元素

首先要实现的是enqueue方法。该方法负责向队列添加新元素。此处一个非常重要的细节是新的项只能添加到队列末尾。

class Queue {
	constructor(){
		this.count = 0;	//{1}
		this.lowestCount = 0;	//{2}
		this.items = {};	//{3}
	}
	
	enqueue(element){
		this.items[this.count] = element;
		this.count++;
	}
}

enqueue 方法和Stack 类中 push 方法的实现方式相同。由于items 属性是一个JavaScript对象,它是一个键值对的集合。要向队列中加人一个元素的话,我们要把count变量作为items对象中的键,对应的元素作为它的值。将元素加入队列后,我们将count变量加1。

②检查队列是否为空

刚刚实现了向队列添加元素的方法,这个要实现是isEmpty方法。如果队列为空,它会返回true,否则返回false(注意该方法和Stack类里的一样)。

class Queue {
	constructor(){
		this.count = 0;	//{1}
		this.lowestCount = 0;	//{2}
		this.items = {};	//{3}
	}
	
	enqueue(element){
		this.items[this.count] = element;
		this.count++;
	}
	
	isEmpty(){
		return this.count - this.lowestCount === 0;
	}
}

③获取队列的长度

要计算队列中有多少元素,我们只需要计算count和lowestCount之间的差值即可。

假设count属性的值为2,lowestCount的值为0。这表示在队列中有两个元素。然后,从队列中移除一个元素,lowestCount的值会变为1,count的值仍然是2。现在队列中只有一个元素了,以此类推。

所以要实现size方法的话,我们只需要返回这个差值即可。

class Queue {
	constructor(){
		this.count = 0;	//{1}
		this.lowestCount = 0;	//{2}
		this.items = {};	//{3}
	}
	
	enqueue(element){
		this.items[this.count] = element;
		this.count++;
	}
	
	isEmpty(){
		return this.count - this.lowestCount === 0;
	}
	
	size(){
		return this.count - this.lowestCount;
	}
	
	/* 也可以像这样实现 isEmpty 方法*/
	// isEmpty(){
	// 	return this.size() === 0;
	// }
}

④从队列移除元素

接下来要实现dequeue方法,该方法负责从队列移除项。由于队列遵循先进先出原则,最先添加的项也是最先被移除的。

class Queue {
	constructor(){
		this.count = 0;	//{1}
		this.lowestCount = 0;	//{2}
		this.items = {};	//{3}
	}
	
	enqueue(element){
		this.items[this.count] = element;
		this.count++;
	}
	
	isEmpty(){
		return this.count - this.lowestCount === 0;
	}
	
	size(){
		return this.count - this.lowestCount;
	}
	
	/* 也可以像这样实现 isEmpty 方法*/
	// isEmpty(){
	// 	return this.size() === 0;
	// }

	dequeue(){
		if(this.isEmpty()){
			return undefined;
		}
		const result = this,items[this.lowestCount]; //{1}
		delete this.items[this.lowestCount]; //{2}
		this.lowestCount++; //{3}
		return result; //{4}
	}
}

首先,我们需要检验队列是否为空。如果为空,我们返回 undefined值。如果队列不为空,我们将暂存队列头部的值(行{1}),以便该元素被移除后(行{2})将它返回(行{4})。我们也需要将lowestCount属性加1(行{3})。

用下面的内部值来模拟dequeue动作。

items = {
	0: 5,
	1: 9
}
count = 2;
lowestCount = 0;

我们需要将键设为0来获取队列头部的元素(第一个被添加的元素是5),删除它,再返回它的值。

在这种场景下,删除第一个元素后,items属性将只会包含一个元素(1:9)。

再次执行dequeue方法的话,它将被移除,因此我们将lowestCount变量从0修改为1。

只有enqueue 方法和 dequeue 方法可以添加和移除元素,这样就确保了Queue类遵循先进先出原则

⑤查看队列头元素

现在来为我们的Queue类实现一些额外的辅助方法。如果想知道队列最前面的项是什么,可以用peek方法。该方法会返回队列最前面的项(把lowestCount作为键名来获取元素值)。

class Queue {
	constructor(){
		this.count = 0;	//{1}
		this.lowestCount = 0;	//{2}
		this.items = {};	//{3}
	}
	
	enqueue(element){
		this.items[this.count] = element;
		this.count++;
	}
	
	isEmpty(){
		return this.count - this.lowestCount === 0;
	}
	
	size(){
		return this.count - this.lowestCount;
	}
	
	/* 也可以像这样实现 isEmpty 方法*/
	// isEmpty(){
	// 	return this.size() === 0;
	// }

	dequeue(){
		if(this.isEmpty()){
			return undefined;
		}
		const result = this,items[this.lowestCount]; //{1}
		delete this.items[this.lowestCount]; //{2}
		this.lowestCount++; //{3}
		return result; //{4}
	}
	
	peek(){
		if(this.isEmpty()){
			return undefined;
		}
		return this.items[this.lowestCount];
	}
}

⑥清空队列

若要清空队列中的所有元素,我们可以调用dequeue方法直到它返回 undefined,也可以简单地将队列中的属性值重设为和构造函数中的一样。

class Queue {
	constructor(){
		this.count = 0;	//{1}
		this.lowestCount = 0;	//{2}
		this.items = {};	//{3}
	}
	
	enqueue(element){
		this.items[this.count] = element;
		this.count++;
	}
	
	isEmpty(){
		return this.count - this.lowestCount === 0;
	}
	
	size(){
		return this.count - this.lowestCount;
	}
	
	/* 也可以像这样实现 isEmpty 方法*/
	// isEmpty(){
	// 	return this.size() === 0;
	// }

	dequeue(){
		if(this.isEmpty()){
			return undefined;
		}
		const result = this,items[this.lowestCount]; //{1}
		delete this.items[this.lowestCount]; //{2}
		this.lowestCount++; //{3}
		return result; //{4}
	}
	
	peek(){
		if(this.isEmpty()){
			return undefined;
		}
		return this.items[this.lowestCount];
	}
	
	clear(){
		this.count = 0;	//{1}
		this.lowestCount = 0;	//{2}
		this.items = {};	//{3}
	}
}

⑦创建toString方法

其实呢到这里,一个简单的Queue类就已经完成了!我们也可以像Stack类一样增加一个toString方法。

class Queue {
	constructor(){
		this.count = 0;	//{1}
		this.lowestCount = 0;	//{2}
		this.items = {};	//{3}
	}
	
	enqueue(element){
		this.items[this.count] = element;
		this.count++;
	}
	
	isEmpty(){
		return this.count - this.lowestCount === 0;
	}
	
	size(){
		return this.count - this.lowestCount;
	}
	
	/* 也可以像这样实现 isEmpty 方法*/
	// isEmpty(){
	// 	return this.size() === 0;
	// }

	dequeue(){
		if(this.isEmpty()){
			return undefined;
		}
		const result = this,items[this.lowestCount]; //{1}
		delete this.items[this.lowestCount]; //{2}
		this.lowestCount++; //{3}
		return result; //{4}
	}
	
	peek(){
		if(this.isEmpty()){
			return undefined;
		}
		return this.items[this.lowestCount];
	}
	
	clear(){
		this.count = 0;	//{1}
		this.lowestCount = 0;	//{2}
		this.items = {};	//{3}
	}
	
	toString(){
		if(this.isEmpty()){
			return '';
		}
		let objString = `${this.items[this.lowestCount]}`;
		for(let i = this.lowestCount + 1; i < this.count; i++){
			objString += `${objString},${this.items[i]}`;
		}
		return objString;
	}
}

在Stack类中,我们从索引值为0开始选代items中的值。由于Queue类中的第一个索引值不一定是0,我们需要从索引值为lowestCount的位置开始迭代队列。

到现在为止呢,我们真的完成了!

Queue 类和Stack类非常类似。主要的区别在于dequeue方法和peek方法,这是由于先进先出和后进先出原则的不同所造成的。

四、使用Queue类

首先要做的是实例化我们刚刚创建的Queue类,然后就可以验证它为空(输出为true,因为我们还没有向队列添加任何元素)。

const queue = new Queue();
console.log(queue.isEmpty());	//输出true

接下来,添加一些元素,添加张三和李四两个元素——现在可以向队列添加任何类型的元素。

queue.enqueue('张三');
queue.enqueue('李四');

console.log(queue.toString());	//输出 张三,李四

再添加另一个元素。

queue.enqueue('王五');
console.log(queue.toString());	//输出 张三,李四,王五
console.log(queue.size());	//输出 3
console.log(queue.isEmpty());	//输出false

queue.dequeue(); // 移除张三

4如果打印队列的内容,就会得到张三、李四、王五这三个元素。因为我们向队列添加了三个元素,所以队列的大小为3(当然也就不为空了)。

下图展示了目前为止执行的所有入列操作,以及队列当前的状态。
在这里插入图片描述

也就是说,我们遵循了先进先出原则。

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

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

相关文章

【解析几何笔记】11.向量的外积运算

11. 向量的外积运算 【注】也可以这么计算 11.1 向量的多重乘积 【命题】任意三个向量&#xff0c; α , β , γ \pmb{\alpha},\pmb{\beta},\pmb{\gamma} α,β,γ&#xff0c; ( α β ) γ ( α ⋅ γ ) β − ( β ⋅ γ ) α (\pmb{\alpha}\times\pmb{\beta})\times\p…

Java 7.4 - 分布式锁

什么是分布式锁&#xff1f; 对于单机多线程&#xff0c;我们使用 ReentrantLock 这类本地锁来控制多个线程对本地共享资源的访问&#xff1b;而对于分布式系统&#xff0c;我们使用 分布式锁 来控制多个服务对共享资源的访问。 分布式锁基本要求&#xff1a; 1、互斥 2、高…

【自由能系列(中级)】自由能与变分自由能——从状态到配置的效益最大化

自由能与变分自由能——从状态到配置的效益最大化 关键词提炼 #自由能 #变分自由能 #状态函数 #配置函数 #效益最大化 #物理系统 #优化问题 第一节&#xff1a;自由能与变分自由能的类比与核心概念 1.1 自由能与变分自由能的类比 自由能和变分自由能可以被视为物理系统的“…

最火视频素材去哪里找?热门的视频素材网站库分享给你

你是否正在寻找那些能够让你的视频作品一鸣惊人的优质素材&#xff1f;如果你还在为如何让视频内容更加出彩而苦恼&#xff0c;那么今天你就来对地方了&#xff01;我将为你介绍几个非常实用且资源丰富的视频素材网站&#xff0c;让你的作品在众多视频中脱颖而出&#xff0c;成…

element的el-steps里的数据处理用switch 循环,处理的数据不要vue响应式的值

element的el-steps我通过v-for循环展示里面的每一行信息我需要处理&#xff0c;我就用了方法 handlerCatalogue来处理&#xff0c; 我重新定义一个数据lineOneIntro &#xff0c;每次return的lineOneIntro &#xff0c;但是会执行103次&#xff0c; 导致我页面卡死&#xff0c;…

SpringBoot 基于iText 根据PDF模板动态生成文件

SpringBoot 基于iText 根据PDF模板动态生成文件, 需要使用 adobe acrobat pro DC这个工具来自定义模板 支持根据PDF模板生成单页或多页PDF文件 adobe acrobat pro DC 自定义模板 下载地址 链接&#xff1a;https://pan.baidu.com/s/1Vn3bIQ5_D17sEZnkF2t7gg?pwdn6o1 提取码…

【hot100篇-python刷题记录】【杨辉三角】

R6-dp篇 印象题&#xff0c;但做法应该改变了 思路&#xff1a;前两行直接写 next[i]cur[i-1]cur[i]&#xff0c;其中next[0]和next[-1] 这样的话&#xff0c;需要创建2个额外的数组空间&#xff0c;而且还要变化 所以考虑动态规划 class Solution:def generate(self, num…

Efficient LoFTR论文阅读(特征匹配)

Efficient LoFTR论文阅读&#xff08;特征匹配&#xff09; 摘要1. 引言2. 相关工作基于检测器的图像匹配无检测器图像匹配 3. 方法3.1. 局部特征提取3.2. 高效的局部特征变换3.3. 准备工作3.4. 聚合注意力机制3.5 粗级匹配模块有效推理策略子像素级细化模块有效的精细特征提取…

[C语言]一、C语言基础(03.函数)

G:\Cpp\C语言精讲 6. 函数 6.1函数的基本使用 6.1.1 为什么需要函数 《街霸》游戏中&#xff0c;每次人物出拳、出脚或跳跃等动作都需要编写50-80行的代码&#xff0c;在每次出拳、出脚或跳跃的地方都需要重复地编写这50-80行代码&#xff0c;这样程序会变得很臃肿&#xff…

目前kimi算不算国内顶级的AI?

利用AI工具批量生成影视短剧推广https://docs.qq.com/doc/DYnl6d0FLdHp0V2ll 从用户体验上讲&#xff0c;我觉得 Kimi 算得上国内的顶级 AI。 现在的大模型产品遍地开花&#xff0c;底层模型原理差异不大&#xff0c;想要在这样的市场环境中生存下来并赢得普通用户认可&#xf…

Go锁 详解

锁 - Go 函数并发编程中&#xff0c;锁是一种同步机制&#xff0c;用于协调对共享资源的访问&#xff0c;防止数据竞争 - Go 中提供了多种类型的锁&#xff0c;每种锁都有不同的特性和适用场景类型 互斥锁&#xff08;mutex&#xff09; 基础锁&#xff0c;只能同时允许一个 g…

【C++ Primer Plus习题】6.5

问题: 解答: #include <iostream> using namespace std;int main() {float salary 0;float tax 0;while (salary>0){cout << "请输入您的工资:";cin >> salary;if (cin.fail())break;if (salary < 5000){tax 0;}else if (salary < 15…

2024 MongoDB中国用户大会倒计时2天!请查收专属参会指南

距离2024 MongoDB中国用户大会即将开幕仅剩2天&#xff0c;我们非常期待与您共同探讨和分享最新的数据库技术与应用经验。为了确保您能够顺利参与本次会议&#xff0c;请查阅属于您的专属温馨提示&#xff01; 活动时间 8月31日09:00-17:30 签到开始&#xff1a;08:00 现场参…

Linux实现异步IO的方法:epoll,posix aio,libaio,io_uring

Linux中异步IO的实现方式大概有以下几种&#xff1a; 1. epoll 熟悉网络编程的人可能会想到select&#xff0c;poll&#xff0c;epoll这些异步IO的方式&#xff0c;但实际上这些方式叫做非阻塞IO&#xff0c;并不是实际意义上的异步IO。因此这些只能用于异步的Socket IO&…

Xline v0.7.0: 一个用于元数据管理的分布式KV存储

Xline是什么&#xff1f;我们为什么要做Xline&#xff1f; Xline是一个基于Curp协议的&#xff0c;用于管理元数据的分布式KV存储。现有的分布式KV存储大多采用Raft共识协议&#xff0c;需要两次RTT才能完成一次请求。当部署在单个数据中心时&#xff0c;节点之间的延迟较低&a…

【C++从小白到大牛】C++的隐式和显示类型转换基础知识讲解

目录 1、C语言中的类型转换 2、C语言和C中可以相互转换的类型总结 C语言&#xff1a; CPP&#xff1a; 3. 为什么C需要四种类型转换 4、C四大强制类型转换 4.1static_cast 4.2 reinterpret_cast 4.3 const_cast 4.4dynamic_cast 注…

吴恩达机器学习笔记 四十五 基于内容的过滤的tensorFlow实现

一个user网络&#xff0c;一个item网络 &#xff0c;使用顺序模型&#xff0c;激活函数选择relu&#xff0c;最后的输出大小都是32。 input_user提取特征&#xff0c;然后把这些特征送给上面的user_NN这个网络得到用户向量vu&#xff0c;再对vu进行标准化&#xff08;用l2范式&…

【最精简】解决访问GitHub慢的问题

我们通过命令行ping两个网站获取对应的IP地址 在windows中&#xff0c;修改hosts文件&#xff0c;路径一般是C:\Windows\System32\drivers\etc&#xff0c;用记事本打开&#xff0c;输入以下内容即可。 // 配置GitHub加速 199.232.69.194 github.global.ssl.fastly.net 140.8…

数据结构与算法 第3天(栈和队列)

栈和队列也是线性表&#xff0c;限制插入和删除的位置只能在端点 栈&#xff08;stack&#xff09; 后进先出 LIFO 表尾进入&#xff0c;表尾删除 一、案例 案例一&#xff1a;进制转换 例子 159转换成八进制 159/819...7 19/82...3 2/80...2 结果为237 案例二&#xff1a;括…

【香橙派系列教程】(二十) 系统移植、交叉编译工具链—OrangePi Zero2 SDK说明

【二十】基于OrangePi Zero2的系统移植—OrangePi Zero2 SDK说明 文章目录 【二十】基于OrangePi Zero2的系统移植—OrangePi Zero2 SDK说明1.使用环境要求2.Linux获取SDK3.首次编译完整SDK 之前我们在使用香橙派时&#xff0c; 都是直接在香橙派上进行代码编译&#xff0c; 但…