当前位置: 首页 > news >正文

JS队列之双端队列介绍

首先先说它的应用场景。例如低代码平台、富文本编辑器上的重做和撤销功能。

然后进入正文:

核心比喻:一艘可以两头装卸货物的长驳船

想象一下,你有一艘很长很长的驳船,船上有很多集装箱的空位,从船头到船尾依次编号 0, 1, 2, 3, ...

普通队列 (Queue):就像一个普通的码头,所有货物都从船尾(Back)装上船 (enqueue),然后只能从船头(Front)卸货 (dequeue)。先进来的货物(集装箱)总是先出去,非常公平。

双端队列 (Deque):现在,你的这艘驳船升级了!它既可以在船尾装货 (addBack),也可以在船头装货 (addFront)。同样,卸货也既可以从船头卸 (removeFront),也可以从船尾卸 (removeBack)。它就像一个两端都有吊机的超级驳船,操作非常灵活。

这就是双端队列的核心思想:一个允许在两端进行添加和移除操作的线性数据结构。

深入理解你的 JavaScript 代码

你的这段代码非常巧妙,它用一个普通的对象 (#items) 来模拟这艘驳船。但它有一个关键的优化,让我们来一步步拆解。

我们船上有两个重要的记录员:

#count:记录船尾下一个空位的编号。货物总是装在这个位置。

#lowestCount:记录船头第一个有货物的集装箱的编号。卸货总是从这里开始。

1. addBack(element) - 从船尾装货
code
JavaScript
download
content_copy
expand_less
addBack(element) {
this.#items[this.#count] = element;
this.#count++;
}

这是最简单的操作。就像在船尾的下一个空位(#count 指示的位置)放上一个集装箱 (element),然后更新下一个空位的编号(#count++)。

船的状态变化:
#items = {}, #count = 0, #lowestCount = 0
addBack('A') -> #items = {0: 'A'}, #count = 1, #lowestCount = 0
addBack('B') -> #items = {0: 'A', 1: 'B'}, #count = 2, #lowestCount = 0

2. removeFront() - 从船头卸货
code
JavaScript
download
content_copy
expand_less
removeFront() {
// ... 省略空检查 ...
const result = this.#items[this.#lowestCount];
delete this.#items[this.#lowestCount];
this.#lowestCount++;
return result;
}

这里是第一个巧妙之处!我们不是把所有集装箱都往前挪一格(那样太费力了),而是直接把船头第一个集装箱 (#items[#lowestCount]) 卸掉,然后宣布:“现在新的船头是下一个位置了!” (#lowestCount++)。

船的状态变化:
#items = {0: 'A', 1: 'B'}, #count = 2, #lowestCount = 0
removeFront() -> 卸掉 'A'
#items = {1: 'B'}, #count = 2, #lowestCount = 1
注意! 船头前面空出来了一个位置 0!我们并没有移动集装箱 'B'。

3. addFront(element) - 从船头装货(最关键的部分)

这是最复杂也最能体现设计思想的地方。现在要在船头加一个集装箱,有三种情况:

情况一:船是空的 (this.isEmpty())
很简单,直接当做从船尾装货就行了。

情况二:船头前面有空位 (this.#lowestCount > 0)
这是最高效的情况!因为我们之前 removeFront() 的时候,在船头留下了空位。现在正好可以利用这些空位。

code
JavaScript
download
content_copy
expand_less
} elseif (this.#lowestCount > 0) {
this.#lowestCount--;
this.#items[this.#lowestCount] = element;
}

我们把新的船头位置往前挪一格 (#lowestCount--),然后把新货物放上去。完美利用了空间!

船的状态变化:
假设当前状态:#items = {1: 'B', 2: 'C'}, #count = 3, #lowestCount = 1 (位置0是空的)
addFront('X') ->
#lowestCount 变成 0。
#items[0] = 'X'
最终状态:#items = {0: 'X', 1: 'B', 2: 'C'}, #count = 3, #lowestCount = 0

情况三:船头前面没有空位 (else)
这是最糟糕、最费力的情况。船头(位置0)已经顶格了,没地方放了。怎么办?只能让船上所有的集装箱都往船尾方向挪一格,给船头腾出一个位置 0 来。

code
JavaScript
download
content_copy
expand_less
} else {
for (let i = this.#count; i > 0; i--) {
this.#items[i] = this.#items[i - 1]; // 所有货物往后挪
}
this.#count++;
this.#lowestCount = 0; // 船头还在0
this.#items[0] = element; // 在腾出的0号位放上新货物
}

这个操作效率很低,所以代码的设计者通过 #lowestCount 机制,尽可能地避免这种情况的发生。

双端队列的现实应用场景

为什么我们需要这么一个“超级驳船”呢?

实现撤销/重做 (Undo/Redo) 功能

场景:你在一个编辑器里写字,或者在画图软件里操作。

应用:

你每执行一个操作(比如输入文字、删除图形),就把它 addBack 到一个双端队列里。

当你点击 “撤销” (Undo) 时,就从队尾 removeBack 一个操作,并执行它的反向操作。

这个被撤销的操作怎么办?可以把它 addFront 到另一个“重做队列”里。

当你点击 “重做” (Redo) 时,就从“重做队列”里 removeFront 一个操作,并重新执行它,再把它 addBack 回原来的操作历史队列。

双端队列的灵活性在这里体现得淋漓尽致。

滑动窗口算法

场景:你需要计算一个巨大数组中,每个长度为 k 的连续子数组(窗口)的最大值或最小值。

应用:

想象一个长度为 k 的窗口从数组的左边滑到右边。

我们可以用一个双端队列来维护当前窗口内“可能的”最大值(或者它们的索引)。

规则:队列从头到尾保持递减。

窗口滑动时:

新元素进入窗口:从队尾 removeBack 所有比新元素小的数,因为它们不可能再成为窗口的最大值了。然后把新元素 addBack 进去。

旧元素离开窗口:检查队首 peekFront 的元素是不是那个刚刚滑出窗口的旧元素。如果是,就 removeFront。

这样,在每一步滑动后,队首的元素永远是当前窗口的最大值。双端队列使得我们不必每次都遍历窗口内的所有元素,极大地提高了效率。

总而言之,双端队列是一个功能强大的工具,它结合了队列和栈的特性,为需要从两端操作数据的复杂问题提供了优雅且高效的解决方案。

代码通过一个巧妙的“浮动船头” (#lowestCount) 机制,优化了前端操作的性能。

http://www.jsqmd.com/news/13294/

相关文章:

  • 实用指南:3D 和 4D 世界建模:综述(下)
  • V-Ray 6.1 插件安装指南|Revit 2019-2024 图文教程
  • 2025 年国内球墨铸铁管厂家最新推荐排行榜:涵盖市政 / 给水 / 水利工程用管,助力采购高效选材
  • 2025 最新铝型材源头厂家推荐排行榜:佛山龙头与新锐品牌深度解析,采购优选指南
  • 2025 年光伏支架设备厂家推荐霸州市邦昊通达冷弯设备有限公司,廊坊 / 霸州 / 北方光伏支架设备 / 光伏支架冲孔机 / 光伏支架角钢成型机 / 光伏支架 C 型钢成型机公司推荐
  • C#使用AForge.NET和EMGU CV开源库实现摄像头视频流捕获与处理
  • Citrix XenApp and XenDesktop 7.15 LTSR - 应用程序和桌面虚拟化
  • Citrix Virtual Apps and Desktops 7 2203 LTSR - 应用程序和桌面虚拟化
  • 2025 年过滤机厂家最新推荐排行榜:聚焦技术创新与市场口碑,精选五家优质企业助力企业选购胶带式/盘式真空/带式/脱水/带式真空过滤机厂家推荐
  • 2025年中国GEO(AI搜索优化)源头厂家Top 10推荐排行:云视科技领跑行业革新
  • easylive-注册 - 详解
  • chrome浏览器无法安装扩展程序?分享二种解决方案
  • Apache Doris 大数据仓库全面解析 - 教程
  • 连接AI与决策:深度解析Palantir的“基石”:本体(Ontology)
  • Java 泛型详解
  • LGP3372 [LG TPLT] 线段树一 学习笔记
  • 鸿蒙应用开发从入门到实战(二十一):ArkUI自定义弹窗组件
  • Day27 | Java集合框架之List接口详解 - 实践
  • 2025年空天信息感知与智能处理国际学术会议(AIPIP 2025)
  • svn常用命令命令
  • 2025 年防撞护栏生产厂家最新推荐榜单:深度剖析各企业产品质量与服务能力,Q235/Q355B/景观/灯光/河道桥梁防撞护栏厂家推荐
  • 人类一败涂地Mac版下载教程|Human Fall Flat Mac安装与游戏玩法详解
  • 第二届航空航天、机械与材料工程国际学术会议 (AMME 2025)
  • 从Salesforce到国产CRM,纷享销客助力顺祥新材料提速提效
  • 再见 Navicat!DataGrip 正式宣布免费!!
  • 蓝牙语音遥控器方案 NRF52840、HS6621
  • 如何本地直升Windows 11 25H2:两种方法超级简单
  • 创意技术专家指南:如何融合编程与创造力
  • 2025 年桥梁护栏厂家最新推荐排行榜:聚焦防撞、景观、不锈钢、铝合金、灯光护栏,精选优质企业助力项目高效选型
  • 2025 年最新推荐!覆盖上海广州杭州等多地的居民同城长途异地跨城日式国际搬家公司优质服务排行榜