摘要:队列是遵行先进先出原则的一组有序的项。优先队列是默认队列的变种,它的元素的添加和移除是基于优先级的。如此循环,直至队列的长度等于,返回胜者行。同时,还掌握了很著名的优先队列循环队列这两种结构。
《学习JavaScript数据结构与算法》读书笔记。
队列是遵行FIFO(First In First Out, 先进先出)原则的一组有序的项。队列再尾部添加新元素,并从顶部移除元素。
在现实中,最常见的队列的例子就是排队。
1.创建队列
现在,我们来创建一个类来表示一个队列。先从最基本的声明类开始:
function Queue(){ // 这里是属性和方法 }
首先,需要一个用户存储队列中元素的数据结构,我们可以使用数组。
var items = [];
接下来,声明一些队列可用的方法:
enqueue(element(s)):进队,向队列尾部添加一个(或多个)新项。
dequeue():移除队列的第一项,并返回被移除的元素。
front():返回队列中第一个元素-最先被添加,也会是最先被移除的元素。(只返回,不移除)。
isEmpty():如果队列为空,返回true,否则,返回false。
size():返回队列的长度。
首先,我们来实现enqueue的方法,这个方法负责向队列中添加新元素。只能是添加到队列的尾部。
this.enqueue = function(element) { items.push(element); }
接下来要实现的是dequeue方法,这个方法负责从队列移除项。由于队列遵循的是先进先出原则,所以最先移除的就是最先添加的,元素是排在数组的第一位。
this.dequeue = function() { return items.shift(); }
只有enqueue方法和dequeue方法可以添加和移除元素,这样就确保了Queue类遵循先进先出原则。
现在来为我们的类实现一些额外的辅助方法:
// front():返回队列中第一个元素 this.front = function() { return items[0]; } // isEmpty():如果队列为空,返回true,否则,返回false this.isEmpty = function() { return items.length === 0; } // size():返回队列的长度 this.size = function() { return items.length; }
完成,我们的Queue类实现好了,现在来看看Queue完整的实现是怎么样的:
function Queue() { var items = []; this.enqueue = function(element) { items.push(element); } this.dequeue = function() { return items.shift(); } this.front = function() { return items[0]; } this.isEmpty = function() { return items.length === 0; } this.clear = function() { items = []; } this.size = function() { return items.length; } this.print = function() { console.log(items.toString()); } }
2.使用Queue类
var queue = new Queue(); console.log(queue.isEmpty()); // 输出 true queue.enqueue("John"); // 添加元素 John queue.enqueue("Jam"); // 添加元素 Jam queue.enqueue("Camila"); // 添加元素 Camila queue.print(); console.log(queue.size); // 输出 3 console.log(queue.isEmpty); // 输出 false queue.dequeue(); // 移除元素 queue.dequeue(); queue.print();
运行上面的代码,我们可以看出,我们已经实现了队列,遵循了先入先出原则。
3.优先队列
上面我们已经实现了一个队列,现在,逐步深入,我们来看看什么是优先队列。
优先队列是默认队列的变种,它的元素的添加和移除是基于优先级的。一个现实的例子就是医院的(急诊科)候诊室。医生会优先处理病情比较严重的患者。
实现一个优先队列,有两种选择:设置优先级,然后在正确的位置添加元素;或者用默认入列操作添加元素,任何按照优先级移除它们。下面,我们将会在正确的位置添加元素,任何用默认你的出列操作。
function PriorityQueue() { var items = []; // {1} function QueueElement(element, priority) { this.element = element; this.priority = priority; } this.enqueue = function(element, priority) { var queueElement = new QueueElement(element, priority); if(this.isEmpty()) { items.push(queueElement); // {2} } else { var added = false; for(var i = 0; i < items.length; i++) { if(queueElement.priority < items.[i].priority) { items.splice(i, 0, queueElement); // {3} added = true; break; } } if(!added) { // {4} items.push(queueElement); } } } // 其他方法与默认队列一样 }
我们创建了一个特殊的元素(行{1}),这个元素包含了要添加到队列的元素及其优先级。
如果队列为空,则直接将元素入列(行{2})。否则,就要进行比较。当找到一个比要添加的元素的priority值更大(优先级更低)时,就将元素插入到它之前(行{3})。
如果要添加的元素的priority指大于任何已有的元素,则直接将其添加到队列的末尾(行{4})。
var priorityQueue = new PriorityQueue(); priorityQueue.enqueue("John", 2); priorityQueue.enqueue("Jam", 1); priorityQueue.enqueue("Sam", 1); priorityQueue.print();
至此,我们已经实现了优先队列,下面,将再介绍一种队列——循环队列
4.循环队列——击鼓传花
循环队列是默认队列的另一种修改版,什么是循环队列呢?举个现实中的例子,记得小时候玩过的传花游戏吗?
几个孩子围成一圈,开始击鼓了,孩子就把花尽快地传递给旁边的人,某一时刻鼓声停止了,传花也就停止了,这个时候花落在谁手上,谁就被淘汰。鼓声响起,继续传花,如此循环,直至只剩下一个孩子,即胜者。
function hotPotato(namelist, num) { var queue = new Queue(); for (var i = 0; i < namelist.length; i++) { // {1} queue.enqueue(namelist[i]); } var eliminated = ""; while (queue.size() > 1) { // {2} for (var i = 0; i < num; i++) { queue.enqueue(queue.dequeue()); // {3} } eliminated = queue.dequeue(); // {4} console.log(eliminated + "在击鼓传花游戏中被淘汰"); } return queue.dequeue(); // {5} } var names = ["john", "jack", "camila", "ingrid", "carl"]; var winner = hotPotato(names, 7); console.log("胜利者: " + winner); //john
首先,先把名单添加到队列里面(行{1})。
当队列的的长度大于1的时候(行{2}),根据指定的一个数字(num)迭代队列,将队列的头一个移除并将其添加到队尾(行{3})。
一旦传递次数达到给定的数字,则删除此时的队列第一项(行{4}),即拿着花的那个人,他将被淘汰。
如此循环,直至队列的长度等于1,返回胜者(行{5})。
5.小结
通过这篇文章的介绍,我们学会了如何用数组构造出队列的类。同时,还掌握了很著名的优先队列、循环队列这两种结构。
附:
JavaScript数据结构和算法系列:
JS 栈
JavaScript设计模式系列:
JavaScript设计模式之策略模式
JavaScript设计模式之发布-订阅模式(观察者模式)-Part1
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/88037.html
摘要:等到主任务队列执行完成时此时已打印,执行存在队列中的函数,任务队列中引入了任务队列来执行的回调函数。在这个的回调函数中使用创建一个的任务,同时在中调用函数创建一个任务。 本文讨论的事件循环均是基于浏览器环境上的,类似nodejs环境下的事件循环与此并不相同。 读者首先要对js单线程事件循环机制以及Promise有基本理解;如果这两个概念不是很清楚,建议先阅读下面两篇文章: THE JA...
队列的定义 队列是遵循先进先出原则的一组有序的项,与栈的不同的是,栈不管是入栈还是出栈操作都是在栈顶操作,队列则是在队尾添加元素,队顶移除,用一个图来表示大概是这样事的:showImg(https://segmentfault.com/img/remote/1460000018133039?w=584&h=294);用一个更形象的例子就是:排队服务,总是先排队的人会先接受服务,当然不考虑插队的情况...
摘要:初始化队列初始化一个存储队列中元素的数据结构,如果未传入默认赋值空数组,传入需先校验类型是否正确。头等舱和商务舱乘客的优先级要高于经济舱乘客。在有些国家,老年人和孕妇或带小孩的妇女登机时也享有高于其他乘客的优先级。 有一天,当回顾自己走过的路时,你会发现这些奋斗不息的岁月,才是最美好的人生。——弗洛伊德 队列,英文 First In First Out 简称 FIFO,遵从先进先出的原...
摘要:而且目前大部分编程语言的高级应用都会用到数据结构与算法以及设计模式。队列在尾部添加新元素,并从顶部移除元素。最新添加的元素必须排在队列的末尾。 前言 JavaScript是当下最流行的编程语言之一,它可以做很多事情: 数据可视化(D3.js,Three.js,Chart.js); 移动端应用(React Native,Weex,AppCan,Flutter,Hybrid App,小程...
阅读 3813·2021-10-12 10:11
阅读 3636·2021-09-13 10:27
阅读 2539·2019-08-30 15:53
阅读 1971·2019-08-29 18:33
阅读 2189·2019-08-29 14:03
阅读 993·2019-08-29 13:27
阅读 3315·2019-08-28 18:07
阅读 762·2019-08-26 13:23