如何实现一个队列

简介: 队列,是一种常见的逻辑数据结构。具备什么特点呢?经常性的我们会听到一个类比“队列就像队伍过桥洞”,队列中的元素遵循了“先进先出、后进后出”的原则。在JavaScript中有很多的方式来实现一个队列,让我们一起来看看都是如何实现的呢?

前言


队列,是一种常见的逻辑数据结构。具备什么特点呢?经常性的我们会听到一个类比“队列就像队伍过桥洞”,队列中的元素遵循了“先进先出、后进后出”的原则。


在JavaScript中有很多的方式来实现一个队列,让我们一起来看看都是如何实现的呢?


方案一:直接操作数组


直接使用数组存储队列元素,模拟队列特点。


上代码~~~


/**
 * @description 基于数组实现队列的类
 */
class QueueArray {
  // 设置私有属性,存储队列元素
  private list: number[] = [];
  /**
   * @method add
   * @description 将元素插入队列 - 队尾元素
   * @param n number 待插入的元素
   */
  add(n: number) {
    this.list.push(n);
  }
  /**
   * @method delete
   * @description 队列进行出队,移除元素 - 队头元素
   * @returns number | undefined
   */
  delete(): number | undefined {
    // 队头元素移除
    return this.list.shift();
  }
  /**
   * @description 队列长度
   */
  get length(): number {
    return this.list.length;
  }
}


接下来我们来测试下性能,同样以10W条数据为例。


// 实例化,创建队列
const queueArray = new QueueArray();
// 检测add入队插入方法的性能
console.time('add');
// 插入10W条数据
for (let i = 0; i < 10 * 10000; i++) {
  queueArray.add(i);
}
// 获取队列长度
console.log(queueArray.length);
console.timeEnd('add');
// 检测delete出队删除元素方法的性能
console.time('delete');
// 这里出队1W条数据
for (let i = 0; i < 10000; i++) {
  queueArray.delete();
}
console.timeEnd('delete');


看下浏览器中的数据展示


网络异常,图片无法展示
|


再次强调下,不同性能电脑设备打印数据略有不同


我们来分析下直接基于数组Array实现的队列复杂度、性能问题。


  1. 在执行add进行入队元素操作时,10W条数据还是非常快的,执行的都是push操作;


  1. 执行delete进行出队操作时,出队了1W条数据,我们看到消耗的时间有了急剧的增加;有小伙伴可能要问为啥会这样呢?在之前的文章数组旋转,来来来,走个K步~中,胡哥说过数组在内存中是有序连续存储的,一旦涉及到数组元素移动的方法,都是非常损耗性能的,如shiftunshiftsplice方法等。也就是说从队头移除一个元素,就需要将剩余的其他元素统一向前移动一位,带来了O(n)O(n)O(n)的时间复杂度。


以上实现虽然达到了目的,却不是我们最想要的。那还有更优雅的方式吗?


方案二:基于栈结构


现在我们采用栈结构模拟实现队列。在这里我们仍然选择数组来实现栈,不过不同于方案一,不再使用shift方法。


设置两个栈 stack1stack2


  1. 每次入队时,向stack1中插入元素;


  1. 每次出队时,先将stack1中的元素依次pop弹出,然后pushstack2中,将stack2中的最后一个元素pop出,然后再将stack2中的元素再依次放回stack1中,这样就完成了出队。


在这样的操作下,pushpop方法都是非常快速的,时间复杂度O(1)O(1)O(1)


/**
 * @description 基于栈结构实现队列
 */
class QueueStack {
  private statck1: number[] = [];
  private statck2: number[] = [];
  /**
   * @method add
   * @description 将元素插入队列 - 队尾元素
   * @param n number 待插入的元素
   */
  add(n: number) {
    this.statck1.push(n);
  }
  /**
   * @method delete
   * @description 队列进行出队,移除元素 - 队头元素
   * @returns number | undefined
   */
  delete(): number | undefined {
    let n;
    // 1. 将stack1中的元素依次取出,放入stack2中
    while ((n = this.statck1.pop()) !== undefined) {
      this.statck2.push(n);
    }
    // 2. 抛出stack2最后一个元素,移除队头元素-即栈顶元素
    const res = this.statck2.push();
    // 3. 然后stack2中元素再依次放入stack1中
    while ((n = this.statck2.pop()) !== undefined) {
      this.statck1.push();
    }
    return res;
  }
  /**
   * @description 队列长度
   */
  get length(): number {
    // 所有的元素都放在stack1中,直接返回stack1的长度即可
    return this.statck1.length;
  }
}


同样的数据条件-10W条数据,我们来看下性能测试。


const queueStack = new QueueStack();
// 检测add入队插入方法的性能
console.time('add - stack');
// 入队10W个元素
for (let i = 0; i < 10 * 10000; i++) {
  queueStack.add(i);
}
// 获取队列长度
console.log(queueStack.length);
console.timeEnd('add - stack');
// 检测delete出队删除元素方法的性能
console.time('delete - stack');
for (let i = 0; i < 10000; i++) {
  queueStack.delete();
}
console.timeEnd('delete - stack');


来来来,看下浏览器中数据:


网络异常,图片无法展示
|


从数据上对比下,add添加队列元素的方法,性能是一样的,相差无几。而delete删除队列元素的方法,性能相差甚大,方案二 - 基于栈结构的实现性能更优。


分析下原因:


  1. delete方法中,有两层while循环可记做O(n)O(n)O(n),执行pushpop方法都是O(1)O(1)O(1)时间复杂度的。从时间复杂度这个标准来看,方案二和方案一都是O(n)O(n)O(n)时间复杂度,但是数组的shift方法涉及到移动数组元素,实际性能明显偏低。


  1. 在方案一种,只有list一个数组变量,空间复杂度记为O(n);方案二中有两个stack1stack2数组变量,空间复杂度也是记为O(n)O(n)O(n),实际内存空间肯定是比方案一多了一倍。虽然空间占用多了,但实际算法执行时间有了非常明显的降低,也就是说空间换时间,是非常值的。


二者比较,我们肯定会选择方案二。


问题?


那还有没有更优的算法实现队列呢,肯定是有的,比如说链表结构,当然这是后话,今天暂且不提。欢迎大家持续关注呦~


相关文章
|
1天前
|
存储 JavaScript 前端开发
JavaScript基础
本节讲解JavaScript基础核心知识:涵盖值类型与引用类型区别、typeof检测类型及局限性、===与==差异及应用场景、内置函数与对象、原型链五规则、属性查找机制、instanceof原理,以及this指向和箭头函数中this的绑定时机。重点突出类型判断、原型继承与this机制,助力深入理解JS面向对象机制。(238字)
|
2天前
|
安全 数据可视化 网络安全
安全无小事|阿里云先知众测,为企业筑牢防线
专为企业打造的漏洞信息收集平台
1303 2
|
3天前
|
云安全 人工智能
2025,阿里云安全的“年度报告”
拥抱AI时代,阿里云安全为你护航~
1448 2
|
2天前
|
人工智能 自然语言处理 API
n8n:流程自动化、智能化利器
流程自动化助你在重复的业务流程中节省时间,可通过自然语言直接创建工作流啦。
337 4
n8n:流程自动化、智能化利器
|
10天前
|
机器学习/深度学习 安全 API
MAI-UI 开源:通用 GUI 智能体基座登顶 SOTA!
MAI-UI是通义实验室推出的全尺寸GUI智能体基座模型,原生集成用户交互、MCP工具调用与端云协同能力。支持跨App操作、模糊语义理解与主动提问澄清,通过大规模在线强化学习实现复杂任务自动化,在出行、办公等高频场景中表现卓越,已登顶ScreenSpot-Pro、MobileWorld等多项SOTA评测。
1429 7
|
21小时前
|
Linux 数据库
Linux 环境 Polardb-X 数据库 单机版 rpm 包 安装教程
本文介绍在CentOS 7.9环境下安装PolarDB-X单机版数据库的完整流程,涵盖系统环境准备、本地Yum源配置、RPM包安装、用户与目录初始化、依赖库解决、数据库启动及客户端连接等步骤,助您快速部署运行PolarDB-X。
214 1
Linux 环境 Polardb-X 数据库 单机版 rpm 包 安装教程
|
3天前
|
人工智能 API 开发工具
Skills比MCP更重要?更省钱的多!Python大佬这观点老金测了一周终于懂了
加我进AI学习群,公众号右下角“联系方式”。文末有老金开源知识库·全免费。本文详解Claude Skills为何比MCP更轻量高效:极简配置、按需加载、省90% token,适合多数场景。MCP仍适用于复杂集成,但日常任务首选Skills。推荐先用SKILL.md解决,再考虑协议。附实测对比与配置建议,助你提升效率,节省精力。关注老金,一起玩转AI工具。
|
11天前
|
人工智能 Rust 运维
这个神器让你白嫖ClaudeOpus 4.5,Gemini 3!还能接Claude Code等任意平台
加我进AI讨论学习群,公众号右下角“联系方式”文末有老金的 开源知识库地址·全免费
1311 16
|
4天前
|
机器学习/深度学习 测试技术 数据中心
九坤量化开源IQuest-Coder-V1,代码大模型进入“流式”训练时代
2026年首日,九坤创始团队成立的至知创新研究院开源IQuest-Coder-V1系列代码大模型,涵盖7B至40B参数,支持128K上下文与GQA架构,提供Base、Instruct、Thinking及Loop版本。采用创新Code-Flow训练范式,模拟代码演化全过程,提升复杂任务推理能力,在SWE-Bench、LiveCodeBench等基准领先。全阶段checkpoint开放,支持本地部署与微调,助力研究与应用落地。
410 1
|
3天前
|
安全 API 开发者
手把手带你使用无影 AgentBay + AgentScope 完成一站式智能体开发部署
阿里云无影 AgentBay 作为一个面向 AI 智能体开发的云端 GUI 沙箱服务,已集成至阿里巴巴通义实验室开源的 AgentScope 框架,助力开发者快速构建安全、高效的智能体应用。
242 1