JS中队列和双端队列实现及应用详解

JS中队列和双端队列实现及应用详解

什么是队列?

队列是指一种线性数据结构,它按照先进先出(FIFO)的原则进行排序。队列只允许在后端(称为tail)进行插入操作,在前端(称为head)进行删除操作。例如,当你在一家银行排队等待服务时,由于先来的人先获得服务的原则,所以你必须在队列中等待,直到你到达前面。当有人从银行窗口出来时,他们排在你的前面的所有人都必须离开,直到你才能接受服务。

在编程中,队列常见的应用场景包括:任务调度,缓存管理以及消息队列等。

队列的实现

使用数组实现队列

最简单的实现方式就是使用数组来模拟队列。我们可以使用push方法往数组的尾部插入元素,使用shift方法从数组的头部删除元素。这样就能够满足队列的先进先出原则。

class Queue {
  constructor() {
    this.elements = [];
  }

  enqueue(element) {
    this.elements.push(element);
  }

  dequeue() {
    return this.elements.shift();
  }

  isEmpty() {
    return this.elements.length == 0;
  }

  size() {
    return this.elements.length;
  }
}

双端队列的实现

双端队列是队列的一种扩展,它允许我们在头部和尾部同时进行插入和删除操作。这种特性使得双端队列非常适合用来实现某些算法和数据结构,如双端搜索、滑动窗口等。

在JavaScript中,我们可以使用数组来模拟双端队列。我们可以使用push方法往数组的尾部插入元素,使用shift方法从数组的头部删除元素,使用unshift方法从数组的头部插入元素,使用pop方法从数组的尾部删除元素。

class Deque {
  constructor() {
    this.elements = [];
  }

  addFront(element) {
    this.elements.unshift(element);
  }

  addBack(element) {
    this.elements.push(element);
  }

  removeFront() {
    return this.elements.shift();
  }

  removeBack() {
    return this.elements.pop();
  }

  isEmpty() {
    return this.elements.length == 0;
  }

  size() {
    return this.elements.length;
  }
}

应用场景

任务调度

在任务调度中,队列被用于维护待执行任务的队列。每个任务都被封装为一个函数,当任务执行完毕时,我们将其从队列中删除。任务调度器不断地从队列中取出任务并执行,直到队列为空。

function taskA() {
  console.log("Task A");
}

function taskB() {
  console.log("Task B");
}

function taskC() {
  console.log("Task C");
}

class Scheduler {
  constructor() {
    this.queue = new Queue();
    this.maxConcurrent = 2;
    this.running = 0;
  }

  addTask(task) {
    this.queue.enqueue(task);
    this.schedule();
  }

  schedule() {
    while (!this.queue.isEmpty() && this.running < this.maxConcurrent) {
      const task = this.queue.dequeue();
      task();
      this.running++;
      setTimeout(() => {
        this.running--;
        this.schedule();
      }, 1000);
    }
  }
}

const scheduler = new Scheduler();
scheduler.addTask(taskA);
scheduler.addTask(taskB);
scheduler.addTask(taskC);

上面的代码中,我们定义了三个任务taskA、taskB和taskC,并将它们添加到任务调度队列中。我们使用Scheduler类来管理任务调度,它的addTask方法用于添加任务。我们使用了一个while循环来检查队列中是否有任务可供执行,同时也保证了我们的任务调度器最多会同时执行两个任务。

滑动窗口

滑动窗口算法是一种用于解决字符串和数组问题的常用算法,它可以用队列来实现。滑动窗口算法用来在一个大字符串中寻找一个长度固定的子串,满足一些限定条件。

function findSubstring(s, t) {
  const n = s.length, m = t.length;
  const ans = [];

  if (n < m) return ans;

  const cntS = new Array(128).fill(0);
  const cntT = new Array(128).fill(0);

  for (let i = 0; i < m; i++) {
    cntT[t.charCodeAt(i)]++;
  }

  const check = () => {
    for (let i = 0; i < 128; i++) {
      if (cntT[i] > cntS[i]) return false;
    }
    return true;
  }

  for (let i = 0; i < m; i++) {
    cntS[s.charCodeAt(i)]++;
  }

  if (check()) ans.push(0);

  for (let i = m; i < n; i++) {
    cntS[s.charCodeAt(i - m)]--;
    cntS[s.charCodeAt(i)]++;
    if (check()) ans.push(i - m + 1);
  }

  return ans;
}

上面的代码中,我们定义了一个findSubstring方法,用于在字符串s中寻找子串t。我们首先统计了子串t中每个字符的出现次数,并存储在cntT数组中。然后,我们设定一个长度为m的窗口,从字符串s的开头向右滑动。每次滑动窗口,我们都会更新cntS数组,它存储了当前窗口中每个字符的出现次数。如果当前窗口中的字符出现次数满足要求,那么我们就将窗口的起始位置加入到答案列表中。

总结

队列和双端队列是非常常见的数据结构,它们具有广泛的应用场景。JavaScript提供了很多实现队列和双端队列的方法,包括使用数组实现,使用链表实现等等。在实际开发中,我们通常会选择最简单、最直接的实现方式,以便能够满足我们的需求。在设计算法和数据结构时,我们需要根据具体情况灵活地选择合适的数据结构以及相应的实现方式。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:JS中队列和双端队列实现及应用详解 - Python技术站

(0)
上一篇 2023年6月8日
下一篇 2023年6月8日

相关文章

  • nodejs中全局变量的实例解析

    下面我将详细讲解“nodejs中全局变量的实例解析”的完整攻略。 什么是全局变量 Node.js中的全局变量是指可以在程序的任何位置访问的变量。在Node.js中,有两种类型的全局变量: 全局对象属性 全局作用域属性 全局对象属性 Node.js中的全局对象是global对象,他包含了Node.js的所有全局属性,如console、process、Buffe…

    node js 2023年6月8日
    00
  • express搭建的nodejs项目使用webpack进行压缩打包

    下面我将详细讲解一下使用Webpack进行打包压缩的完整攻略: 确认前置环境 在进行Webpack的安装和使用之前,首先确认一下系统中是否已经安装好Node.js。如果没有安装,可以到官网上下载对应系统的安装文件,然后按照步骤进行安装。Node.js的安装完成之后,可以在命令行中输入node -v来验证一下是否已经安装好。 安装Webpack 在Node.j…

    node js 2023年6月8日
    00
  • 详解nodeJs文件系统(fs)与流(stream)

    下面是对Node.js文件系统(fs)和流(stream)的详解攻略。 fs模块的介绍 Node.js的fs模块提供了一组丰富的API用于文件系统操作,包括文件的读取、写入、修改、删除等。该模块使用同步或异步的方式访问文件系统,可以操作各种类型的文件,包括文本、图片、视频、音频等。 fs的常见API 以下是一些最常用的fs API: 读取文件: fs.rea…

    node js 2023年6月8日
    00
  • director.js实现前端路由使用实例

    下面为您详细讲解”director.js实现前端路由使用实例”的完整攻略。 一、什么是director.js? director.js是一个用于前端路由的JavaScript库。通过director.js,我们可以轻松地实现前端路由功能,使得我们的前端页面可以实现多页面应用的功能,提高了用户的交互体验。 二、如何使用director.js? 1. 引入dir…

    node js 2023年6月8日
    00
  • 初学者如何快速搭建Express开发系统步骤详解

    下面我为你详细讲解“初学者如何快速搭建Express开发系统步骤详解”: 1. 安装Node.js和npm 首先,需要安装Node.js和npm。如果你还没有安装过这两个工具,请先在官网下载安装。 2. 初始化项目 在命令行中进入项目存放的目录,并执行以下命令: npm init 按照提示输入项目信息,比如项目名称、描述、作者等等。这个过程会生成一个pack…

    node js 2023年6月8日
    00
  • Nodejs调用Dll模块的方法

    当我们需要在Node.js中使用C++编写的动态链接库(DLL)时,就需要调用DLL模块了。下面是一份详细的Node.js调用DLL模块的攻略,包含以下内容: 确认操作系统(Windows / Linux)支持动态链接库(DLL)。 编写C++ DLL模块并使用“__stdcall”或“extern ‘C’”调用约定标记。在导出函数之前,必须使用“exter…

    node js 2023年6月8日
    00
  • node.js实现websocket的即时通讯详解

    “node.js实现websocket的即时通讯详解”的攻略如下: 什么是 WebSocket WebSocket 是一种在单个 TCP 连接上进行双向通信的网络协议。它使得服务器可以直接向客户端推送数据,而不需要客户端轮询服务器获取数据。 实现 WebSocket 的方法 在 Node.js 中,可以使用 ws 模块来实现 WebSocket。下面是一个基…

    node js 2023年6月8日
    00
  • Node.js实现分片上传断点续传示例详解

    首先,为了实现分片上传断点续传,我们需要使用Node.js提供的相关模块和技术。具体来说,我们需要用到http模块和fs模块。 步骤如下: 1.创建一个基于http模块的服务器,用于接收上传的文件,并为每一个上传的文件创建一个唯一的标识(例如文件名、UUID等),并将这些标识保存到一个数组中,以便用于断点续传。 示例代码: const http = requ…

    node js 2023年6月8日
    00
合作推广
合作推广
分享本页
返回顶部