3. 队列
3.1 概念
-
受限的线性结构
-
FIFO(First in first out) 先进先出
-
只允许在front进行删除操作
-
只允许在rear进行插入操作
-
-
线程队列(js不支持多线程):
- 开发中为多个任务并行处理,通常会开启多个线程
- 不能同时大量线程运行处理任务,会占用过多资源
- 故开启线程处理任务会使用线程队列
- 线程队列按照次序启动线程,处理相应的任务
-
事件队列
- 通过队列的方式处理多个任务
3.2 封装与测试
-
实现方式
- 基于数组实现
- 基于链表实现
-
队列类的创建(数组方式)
- 创建一个Queue构造函数,用户创建队列的类
- 在构造函数中,定义一个变量用于保存当前队列对象中的所有元素(与创建栈很相似)
- 该变量是数组类型,队列添加元素或删除元素通过该数组方法完成
- 队列与栈有一些相关的操作方法
-
队列常见操作
enqueue(ele)
dequeue()
front()
isEmpty()
size()
toString()
-
封装:
export class Queue{ constructor(){ this.items = [] } //队列尾部添加一个或多个新的项 enqueue(ele){ this.items.push(ele) } //移除队列最前面的项并返回被移除的元素 dequeue(){ return this.items.shift() } //返回队列最前面的那个项(不进行任何操作) front(){ if(this.items.length === 0)return null;//避免越界发生 return this.items[0] } //判断队列是否为空 isEmpty(){ return this.items.length === 0; } //返回队列包含的元素个数 size(){ return this.items.length; } }
测试:
import {Queue} from "./queue" const queue = new Queue(); queue.enqueue("abc"); queue.enqueue("bcd"); queue.enqueue("cde"); console.log(queue.items); console.log(queue.dequeue()); console.log(queue.front()); console.log(queue.items);
3.3 应用
-
击鼓传花
-
题目描述:几个人围成一圈开始数数,数到某个特定数字的人自动淘汰,最后剩下的人获得胜利,请问最后剩下的是原来在哪个位置上的人
-
构思:封装一个基于队列的函数
- 参数:所有参与人的姓名,特定的数字
- 结果:最终剩下的一人的姓名
-
实现:
export function passGame(nameList,num){ //1.创建队列 const queue = new Queue(); for(let i = 0;i<nameList.length;i++){ queue.enqueue(nameList[i]); } //2.循环进出,把最头部的取出再放入队列末尾, while(queue.size()>1){ for(let i = 0;i<num-1;i++){ queue.enqueue(queue.dequeue()) } queue.dequeue();//序数num-1就是第num个,需要淘汰不放回 } return queue.front(); }
-
3.4 优先级队列
-
插入一个元素时考虑该数组的优先级,与其他数据优先级进行比较,比较完成后得出元素在队列中正确的位置
-
其他处理方式与基本队列处理方式一致
-
主要考虑问题:
- 每个元素不再只是一个数据,而是包含数据的优先级
- 添加方式中,需要根据优先级放入正确的位置
-
应用:计算机中通过优先级队列来重新排序队列中任务的顺序
每个线程处理的任务重要性不同,我们可以通过优先级的大小来决定该线程在队列中被处理的次序
-
实现:
- 封装元素和优先级一起,(可以封装一个新的构造函数)
- 添加元素时要先将元素优先级与队列里已经存在的元素优先级进行比较以获取自己正确的位置
- 可以继承普通队列类
class QueueElement{ constructor(element,priority){ this.element = element; this.priority = priority; } } export class PriorityQueue extends Queue { //重写父类进入队列的方法 enqueue(element,priority){ //1.创建QueueElement对象 const queueElemnet = new QueueElement(element,priority); //2.考虑如何插入新的元素 if(this.isEmpty()){ this.items.push(queueElement); }else{ //设置一个信号量 因为可能要插入的优先级最低,那么就不会有插到已有元素前面的情况 let added = false; for(let i=0;i<this.items.length;i++){ //设置数字越小优先级越高,这里说明应该插到第I位 if(this.items[i].priority>queueElement.priority){ this.items.splice(i,0,queueElemnet); added = true; break; } } if(!added){ //优先级最低,直接放到最后 this.items.push(queueElement); } } } }
测试:
const queue = new PriorityQueue(); queue.enqueue("aaa",111); queue.enqueue("bbb",11); queue.enqueue("ccc",20); //在forEach函数中传入一个回调函数,该回调函数接收数组中的每个元素作为参数 queue.items.forEach(item =>{ console.log(item.element,item.priority) })