JavaScript数据结构——队列的实现与应用
队列与栈不同,它遵从先进先出(FIFO——First In First Out)原则,新添加的元素排在队列的尾部,元素只能从队列头部移除。
我们在前一篇文章中描述了如何用JavaScript来实现栈这种数据结构,这里我们对应地来实现队列。
function Queue() {
let items = [];
// 向队列添加元素(一个或多个)
this.enqueue = function (element) {
if (element instanceof Array) items = items.concat(element);
else items.push(element);
};
// 从队列移除元素
this.dequeue = function () {
return items.shift();
};
// 返回队列中的第一个元素
this.front = function () {
return items[0];
};
// 判断队列是否为空
this.isEmpty = function () {
return items.length === 0;
};
// 返回队列的长度
this.size = function () {
return items.length;
};
// 清空队列
this.clear = function () {
items = [];
};
// 打印队列内的所有元素
this.print = function () {
console.log(items.toString());
};
}
与栈的实现方式类似,唯一不同的是从队列移除元素时取的是队列头部的元素(最先添加的),而栈则是取的顶部元素(最后添加的)。下面是一些测试用例及返回结果:
let queue = new Queue();
console.log(queue.isEmpty()); // true queue.enqueue('John');
queue.enqueue(['Jack', 'Camila']);
queue.print(); // John,Jack,Camila
console.log(queue.size()); //
console.log(queue.isEmpty()); // false
console.log(queue.front()); // John console.log(queue.dequeue()); // John
queue.print(); // Jack,Camila queue.clear();
queue.print(); //
注意,我们允许批量向队列中添加元素,为此我们需要判断enqueue方法的参数类型,如果参数是数组,则用concat()函数连接两个数组,如果参数不是数组,则直接用push()函数将元素添加到队列中。
与栈的实现方式一样,这里我们也同样给出用ES6的WeakMap类来实现的队列版本。
let Queue = (function () {
const items = new WeakMap();
class Queue {
constructor() {
items.set(this, []);
}
enqueue (element) {
let q = items.get(this);
if (element instanceof Array) items.set(this, q.concat(element));
else q.push(element);
};
dequeue () {
let q = items.get(this);
return q.shift();
};
front () {
return items.get(this)[0];
};
isEmpty () {
return items.get(this).length === 0;
};
size () {
return items.get(this).length;
};
clear () {
items.set(this, []);
};
print () {
console.log(items.get(this).toString());
};
}
return Queue;
})();
这两个版本的执行结果是一样的,它们的区别我们在前一篇文章中已经提及过了,这里不再赘述。
优先队列
所谓优先队列,顾名思义,就是说插入到队列中的元素可以根据优先级设置先后顺序。优先级越高位置越靠前,优先级越低位置越靠后。假设优先级用数字来表示,如果数字越小表示的优先级越高,形成的队列就称之为最小优先队列,反之则称之为最大优先队列。下面是实现的代码:
function PriorityQueue() {
let items = [];
// 向队列添加元素(一个或多个)
// 参数obj的数据格式:{element, priority}
this.enqueue = function (obj) {
if (obj instanceof Array) {
for (let i = 0, ci; ci = obj[i]; i++) {
this.enqueue(ci);
}
}
else {
let added = false;
for (let i = 0, ci; ci = items[i]; i++) {
// 最小优先级,即将priority值小的元素插入到队列的前面
if (obj.priority < ci.priority) {
items.splice(i, 0, obj);
added = true;
break;
}
}
// 如果元素没有插入到队列中,则默认加到队列的尾部
if (!added) items.push(obj);
}
};
// 从队列移除元素
this.dequeue = function () {
return items.shift();
};
// 返回队列中的第一个元素
this.front = function () {
return items[0];
};
// 判断队列是否为空
this.isEmpty = function () {
return items.length === 0;
};
// 返回队列的长度
this.size = function () {
return items.length;
};
// 清空队列
this.clear = function () {
items = [];
};
// 打印队列内的所有元素
this.print = function () {
items.forEach(function (item) {
console.log(`${item.element} - ${item.priority}`);
});
};
}
可以看到,唯一有区别的只有enqueue方法。我们规定所有添加到优先队列的元素都必须满足{element, priority}这种JSON格式,以保证队列中的每一个元素都有一个priority属性来表示优先级。如果要添加的元素的优先级和队列中已有元素的优先级相同,仍然遵循队列的先进先出原则。如果队列中所有元素的优先级比要添加的元素的优先级都高,则将元素添加到队列的末尾。我们将print()方法也做了一些调整,以方便查看输出结果。
let queue = new PriorityQueue();
console.log(queue.isEmpty()); // true queue.enqueue({element: 'John', priority: 2});
queue.enqueue([{element: 'Jack', priority: 1}, {element: 'Camila', priority: 1}]);
queue.print(); // Jack,Camila,John
由于John的优先级比其它两个低,所以它被排在了最后面。虽然Jack和Camila的优先级相同,但是Jack是在Camila之前先插入到队列中的,所以Jack排在了Camila之前,这也符合了我们的预期。
循环队列
我们用一个小游戏“击鼓传花”来说明循环队列在实际中的应用。
function hotPotato(nameList, num) {
let queue = new Queue();
for (let i = 0, ci; ci = nameList[i]; i++) {
queue.enqueue(ci);
}
let eliminated = '';
while(queue.size() > 1) {
for (let i = 0; i < num; i ++) {
queue.enqueue(queue.dequeue());
}
eliminated = queue.dequeue();
console.log(`${eliminated} has been eliminated.`);
}
return queue.dequeue();
}
let names = ['John', 'Jack', 'Camila', 'Ingrid', "Carl"];
let winner = hotPotato(names, 7);
console.log(`The winner is: ${winner}`);
在这个游戏中,我们传入由五个名字组成的数组,用来表示参加游戏的五个人,数字7表示每一轮要传递的次数。在每一个过程中,我们从队列头部取出一个元素加到队列的尾部,当次数用完的时候,将队列头部的元素取出来,作为这一轮中被淘汰的人。让我们来看一下具体的执行过程,一开始队列中的顺序是John, Jack, Camila, Ingrid, Carl,然后传递7次:
1. Jack, Camila, Ingrid, Carl, John
2. Camila, Ingrid, Carl, John, Jack
3. Ingrid, Carl, John, Jack, Camila
4. Carl, John, Jack, Camila, Ingrid
5. John, Jack, Camila, Ingrid, Carl
6. Jack, Camila, Ingrid, Carl, John
7. Camila, Ingrid, Carl, John, Jack
之后从队列中取出的是Camila。反复执行上述过程,直到队列中的元素只剩一个,这个就是最后的赢家!
下面是完整的执行结果:
Camila has been eliminated.
Jack has been eliminated.
Carl has been eliminated.
Ingrid has been eliminated.
The winner is: John
下一章我们继续来看看如何用JavaScript来实现链表。
JavaScript数据结构——队列的实现与应用的更多相关文章
- JavaScript数据结构——队列的实现
前面楼主简单介绍了JavaScript数据结构栈的实现,http://www.cnblogs.com/qq503665965/p/6537894.html,本次将介绍队列的实现. 队列是一种特殊的线性 ...
- javascript数据结构——队列
队列是一种先进先出的数据结.队列只能在队尾插入元素,在队首删除元素,这点和栈不一样.它用于存储顺序排列的数据.队列就像我们日常中的排队一样,排在最前面的第一个办理业务,新来的人只能在后面排队.队列这种 ...
- javascript数据结构-队列
gihub博客地址 队列(Queue)是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表.进行插 ...
- JavaScript 数据结构与算法之美 - 线性表(数组、栈、队列、链表)
前言 基础知识就像是一座大楼的地基,它决定了我们的技术高度. 我们应该多掌握一些可移值的技术或者再过十几年应该都不会过时的技术,数据结构与算法就是其中之一. 栈.队列.链表.堆 是数据结构与算法中的基 ...
- JavaScript数据结构——图的实现
在计算机科学中,图是一种网络结构的抽象模型,它是一组由边连接的顶点组成.一个图G = (V, E)由以下元素组成: V:一组顶点 E:一组边,连接V中的顶点 下图表示了一个图的结构: 在介绍如何用Ja ...
- 学习javascript数据结构(一)——栈和队列
前言 只要你不计较得失,人生还有什么不能想法子克服的. 原文地址:学习javascript数据结构(一)--栈和队列 博主博客地址:Damonare的个人博客 几乎所有的编程语言都原生支持数组类型,因 ...
- 数据结构与算法JavaScript (二) 队列
队列是只允许在一端进行插入操作,另一个进行删除操作的线性表,队列是一种先进先出(First-In-First-Out,FIFO)的数据结构 队列在程序程序设计中用的非常的频繁,因为javascript ...
- javascript数据结构与算法---队列
javascript数据结构与算法---队列 队列是一种列表,不同的是队列只能在队尾插入元素,在队首删除元素.队列用于存储按顺序排列的数据,先进先出,这点和栈不一样(后入先出).在栈中,最后入栈的元素 ...
- JavaScript数据结构——栈和队列
栈:后进先出(LIFO)的有序集合 队列:先进先出(FIFO)的有序集合 --------------------------------------------------------------- ...
随机推荐
- linux服务器无telnet等测试工具,测试http+json服务连通性
1. 问题描述: 1.公司内部服务器需要通过http接口方式访问另一公司内部接口服务器. 2.申请信息安全开通访问权限,但是只能开通到服务器+端口号,例如:192.168.1:8080,无ping权限 ...
- 剑指offer第二版-2.实现单例模式
面试题2:实现单例模式 题目要求: 设计一个类,只能生成该类的一个实例. /** * 单例模式 * 定义:指实现了特殊模式的类,该类仅能被实例化一次,产生唯一的一个对象 * 应用举例:windows的 ...
- C语言指针专题——序
看到好多的C语言初学者学到指针时,都觉得指针怎么那么难啊!我也想起了我当时学习指针时遇到的困难,确实很难!到底是教程写的不好呢,还是老师教的不好呢?我觉得都有. 网上搜索指针讲解的资料很多,我也看了不 ...
- MyBatis 一对多映射
From<MyBatis从入门到精通> <!-- 6.1.2.1 collection集合的嵌套结果映射 和association类似,集合的嵌套结果映射就是指通过一次SQL查询将所 ...
- py+selenium 直接给日期赋值,控制台调试报错【已解决】
目标:给带日期控件的输入框赋值. 百度去搜索让你各种去只读readonly属性,再send_keys 方法: 其实既然可以去除readonly属性,那就可以直接给属性赋值,将两行代码缩为一行. dri ...
- [Spring-Cloud-Alibaba] Sentinel 整合RestTemplate & Feign
Sentinel API Github : WIKI Sphu (指明要保护的资源名称) Tracer (指明调用来源,异常统计接口) ContextUtil(标示进入调用链入口) 流控规则(针对来源 ...
- .NET CORE 微信小程序消息验证的坑
进入微信小程序,点击开发->选择消息推送->扫码授权,填写必要参数 进入接口开发: /// <summary> /// 验证小程序 /// </summary> / ...
- struct模块(用于对象的压缩)
6.27自我总结 struct模块 1.struct模块中的函数 函数 return explain pack(fmt,v1,v2-) string 按照给定的格式(fmt),把数据转换成字符串(字节 ...
- [leetcode] 19. Remove Nth Node From End of List (Medium)
原题链接 删除单向链表的倒数第n个结点. 思路: 用两个索引一前一后,同时遍历,当后一个索引值为null时,此时前一个索引表示的节点即为要删除的节点. Runtime: 13 ms, faster t ...
- mysql之char、varchar、text对比
mysql5.0.3以后,n都表示字符数(varchar(n)) 检索效率 char > varchar > text 当varchar长度超过255之后,跟text一致,但是设置varc ...