【JavaScript数据结构系列】04-优先队列PriorityQueue

码路工人 CoderMonkey

转载请注明作者与出处

## 1. 认识优先级队列

经典的案例场景:

  • 登机时经济舱的普通队列与头等舱的优先级队列
  • 股票交易时基于时间和价格的成交规则上,量大优先的优先级队列

再用我们打饭的例子:
假定规则:饥饿等级0级最高,需要马上进食
下图同学C优先级高于同学B,插队在同学A后面

2. 代码实现

注:

ES6 版的代码实现请查看 npm 包 data-struct-js 代码

Github/Gitee 上都能找到

npm install data-struct-js

在队列 Queue 的基础上,我们来实现一下优先级队列。

  • 优先级队列只在入队操作上与普通队列不同,其它方法相同
  • 参考上一节里的基于栈实现的队列,也稍稍修改下队列实现的代码

入队操作实现分析:

  • 在创建元素时,我们需要一个优先级参数/字段(priority)
  • 并对优先级做检查,以及默认值设置
  • 空队列时直接入队
  • 非空时,从队列头部开始比对每一个元素,新元素优先级高时插入
  • 比对到最后一个也没能插入时(新元素优先级最低)添加到队尾

主要是 enqueue 方法和 QueueElement 的封装。

// 优先队列
function PriorityQueue() {
this.__items = [] /**
*队列元素对象
*优先级默认为最低
*/
function QueueElement(element, priority) {
// check priority
if(typeof(priority) != 'number' || Number.isNaN(priority)) {
// min-level: Infinity
priority = Infinity
}
this.__element = element
// max-level: 0
this.__priority = priority QueueElement.prototype.priority = function() {
return this.__priority
} QueueElement.prototype.toString = function() {
return this.__element.toString.apply(this.__element)
}
} // 入队方法
PriorityQueue.prototype.enqueue = function(element, priority) {
var queueElement = new QueueElement(element, priority) // 空队列时直接入队
if(this.__items.length === 0) {
this.__items.push(queueElement)
}
// 非空队列入队需比较优先级
else {
var added = false
for(var i=0;i<this.__items.length;i++) {
if(queueElement.priority() < this.__items[i].priority()) {
this.__items.splice(i, 0, queueElement)
added = true
break
}
}
if(!added) {
this.__items.push(queueElement)
}
}
}
}

自己封装的优先级队列中优先级priority也可以作为复杂对象上的一个属性,无需另传参数

完整代码(用到的上一节中的 deepCopy 方法也一并贴上吧)

PriorityQueue.js

这里为了方便查看代码写全了,

实际上重复的部分可以继承普通队列

// 优先队列
function PriorityQueue() {
this.__items = [] /**
*队列元素对象
*优先级默认为最低
*/
function QueueElement(element, priority) {
// check priority
if(typeof(priority) != 'number' || Number.isNaN(priority)) {
// min-level: Infinity
priority = Infinity
}
this.__element = element
// max-level: 0
this.__priority = priority QueueElement.prototype.priority = function() {
return this.__priority
} QueueElement.prototype.toString = function() {
return this.__element.toString.apply(this.__element)
}
} // 入队方法
PriorityQueue.prototype.enqueue = function(element, priority) {
var queueElement = new QueueElement(element, priority) // 空队列时直接入队
if(this.__items.length === 0) {
this.__items.push(queueElement)
}
// 非空队列入队需比较优先级
else {
var added = false
for(var i=0;i<this.__items.length;i++) {
if(queueElement.priority() < this.__items[i].priority()) {
this.__items.splice(i, 0, queueElement)
added = true
break
}
}
if(!added) {
this.__items.push(queueElement)
}
}
} PriorityQueue.prototype.dequeue = function() {
return this.getItems().shift()
} PriorityQueue.prototype.front = function () {
return this.__items.length === 0 ? undefined : this.getItems()[0]
} PriorityQueue.prototype.getItems = function() {
return deepCopy(this.__items)
} PriorityQueue.prototype.isEmpty = function () {
return this.__items.length === 0
} PriorityQueue.prototype.size = function () {
return this.__items.length
} PriorityQueue.prototype.clear = function () {
this.__items.length = 0
} PriorityQueue.prototype.toString = function () {
var arrStr = this.__items.map((qe)=>{
return qe.toString()
})
return arrStr.join('\r\n')
}
}
function deepCopy(source) {
var dest
if(Array.isArray(source)) {
dest = []
for (let i = 0; i < source.length; i++) {
dest[i] =deepCopy(source[i])
}
}
else if(toString.call(source) === '[object Object]') {
dest = {}
for(var p in source){
if(source.hasOwnProperty(p)){
dest[p]=deepCopy(source[p])
}
}
}
else {
dest = source
}
return dest
}

测试一下

var pq = new PriorityQueue()

pq.enqueue({name: 'A-First Element | Priority:1', age: 18, toString: function(){return this.name}}, 1)
pq.enqueue({name: 'B-Second Element | Priority:3', age: 18, toString: function(){return this.name}}, 3)
pq.enqueue({name: 'C-Third Element | Priority:2', age: 18, toString: function(){return this.name}}, 2) console.log(pq.toString())

以优先级分别为 1 -> 3 -> 2 的顺序添加元素,
输出结果为:

A-First Element | Priority:1
C-Third Element | Priority:2
B-Second Element | Priority:3

收工。


做了一份 npm 工具包 data-struct-js
基于 ES6 实现的 JavaScript 数据结构,
虽然这个小轮子很少会被使用,
也许对于初学者学习 JavaScript 会有点帮助。
只要简单 install 一下即可,感兴趣的话还可以去
GitHub / Gitee 看源码。(来 Star 一个吧)

npm install data-struct-js --save-dev

https://github.com/CoderMonkie/data-struct-js

https://gitee.com/coder-monkey/data-struct-js

最后,感谢您的阅读和支持~


-end-

【JavaScript数据结构系列】04-优先队列PriorityQueue的更多相关文章

  1. 【JavaScript数据结构系列】03-队列Queue

    [JavaScript数据结构系列]03-队列Queue 码路工人 CoderMonkey 转载请注明作者与出处 1. 认识队列Queue结构 队列,跟我们的日常生活非常贴近,我们前面举例了食堂排队打 ...

  2. 【JavaScript数据结构系列】00-开篇

    [JavaScript数据结构系列]00-开篇 码路工人 CoderMonkey 转载请注明作者与出处 ## 0. 开篇[JavaScript数据结构与算法] 大的计划,写以下两部分: 1[JavaS ...

  3. JavaScript进阶系列04,函数参数个数不确定情况下的解决方案

    本篇主要体验函数参数个数不确定情况下的一个解决方案.先来看一段使用函数作为参数进行计算的实例. var calculate = function(x, y, fn) { return fn(x, y) ...

  4. 【JavaScript数据结构系列】07-循环链表CircleLinkedList

    [JavaScript数据结构系列]07-循环链表CircleLinkedList 码路工人 CoderMonkey 转载请注明作者与出处 1. 认识循环链表 首节点与尾节点相连的,就构成循环链表.其 ...

  5. 【JavaScript数据结构系列】05-链表LinkedList

    [JavaScript数据结构系列]05-链表LinkedList 码路工人 CoderMonkey 转载请注明作者与出处 ## 1. 认识链表结构(单向链表) 链表也是线性结构, 节点相连构成链表 ...

  6. 【JavaScript数据结构系列】06-双向链表DoublyLinkedList

    [JavaScript数据结构系列]06-双向链表DoublyLinkedList 码路工人 CoderMonkey 转载请注明作者与出处 1. 认识双向链表 不同于普通链表/单向链表,双向链表最突出 ...

  7. 【JavaScript数据结构系列】02-栈Stack

    [JavaScript数据结构系列]02-栈Stack 码路工人 CoderMonkey 转载请注明作者与出处 ## 1. 认识栈结构 栈是非常常用的一种数据结构,与数组同属线性数据结构,不同于数组的 ...

  8. 【JavaScript数据结构系列】01-数组Array

    [JavaScript数据结构系列]01-数组Array 码路工人 CoderMonkey 转载请注明作者与出处 # [JavaScript数据结构系列] # 01-数组Array 数组: 是有序的元 ...

  9. 算法&数据结构系列 -- 堆(优先队列)

    前言 话说新开的博客十分好用... 所以,我打算开一个坑,名曰[算法系列]. 什么意思--从名字泥应该就猜得出来... 废话不多说,进入正文~~ 正文 原理 首先,堆是一颗棵二叉树.. 其次,堆是一棵 ...

随机推荐

  1. Mysql 字符串拆分 OR 一行转多行

    Mysql 字符串拆分 OR 一行转多行 需要了解的的几个mysql 函数: A.substring_index():字符串截取 substring_index(str,delim,count)   ...

  2. python selenium(用例断言)

    1.if ...else ...判断进行断言 from time import * from selenium import webdriver "): driver = webdriver ...

  3. Android EventBus踩坑,Activity接收不了粘性事件。

    注解问题 EventBus 的 粘性事件,可以让 成功注册后的 Activity.Fragment 后再接收处理 这一事件. 但是今晚写代码时,突然发现粘性事件,发送不成功了.??? 具体情况是:我在 ...

  4. DataHub——实时数据治理平台

    DataHub 首先,阿里云也有一款名为DataHub的产品,是一个流式处理平台,本文所述DataHub与其无关. 数据治理是大佬们最近谈的一个火热的话题.不管国家层面,还是企业层面现在对这个问题是越 ...

  5. Z - New Year Tree CodeForces - 620E 线段树 区间种类 bitset

    Z - New Year Tree CodeForces - 620E 这个题目还没有写,先想想思路,我觉得这个题目应该可以用bitset, 首先这个肯定是用dfs序把这个树转化成线段树,也就是二叉树 ...

  6. I - Coins dp

    http://acm.hdu.edu.cn/showproblem.php?pid=2844 这个题目是一个多重背包转化成01背包 题意: Whuacmers拥有bi个面值为ai的硬币,现在他要用这些 ...

  7. IDEA的窗口布局设置

    修改idea的窗口布局 idea默认的窗口模式是如: 可以通过File->Appearance->Window Options->勾选 Widescreen tool window ...

  8. 【译】Using .NET for Apache Spark to Analyze Log Data

    .NET for Spark可用于处理成批数据.实时流.机器学习和ad-hoc查询.在这篇博客文章中,我们将探讨如何使用.NET for Spark执行一个非常流行的大数据任务,即日志分析. 1 什么 ...

  9. 用Python快速实现一个垃圾分类APP|附带微信小程序

    最近北京开始实行垃圾分类,导致大家对垃圾的研究热度突然涨高,垃圾们也纷纷表示从来没有获得过这么高的关注度.其实,上海市去年已经开始实行,网上已经有不少成熟的教程了,像什么<垃圾分类从入门到精通& ...

  10. C# 9.0 新特性预览 - 空参数校验

    C# 9.0 新特性预览 - 空参数校验 前言 随着 .NET 5 发布日期的日益临近,其对应的 C# 新版本已确定为 C# 9.0,其中新增加的特性(或语法糖)也已基本锁定,本系列文章将向大家展示它 ...