队列的概念:
队列是遵循FIFO(First In First Out,先进先出,也称为先来先服务)原则的一组有序的项。队列在尾部添加新元素,并在头部移除元素,队列的元素也可以是任何类型的。
队列的特点:
先进先出,最新添加的元素必须排在队列的末尾,最先移除的元素必须是头部第一个元素
生活中的队列:
在电影院, 自助餐厅, 杂货店收银台,我们所排成的队伍就是队列,排在第一位的人会先接受服务
js语法定义队列及队列的基本方法:
首先是创建一个类来表示一个队列,从基本的属性,方法的声明开始,代码如下:
//声明栈和栈的属性和方法
function Queue() {
this.items = [];//保存队列中元素的数组
this.enqueue = enqueue;//进队列(从尾部进)
this.dequeue = dequeue;//出队列(从头部出)
this.front = front;//队列中第一个元素
this.size = size;//队列中的元素个数
this.isEmpty = isEmpty;//判断队列中是否有元素
this.print = print;//打印队列元素
}
重写队列的相关方法,代码如下:
function enqueue(element) {//进队列
this.items.push(element);
}
function dequeue() {//出队列
return this.items.shift();
}
function front() {//查看队列头元素
return this.items[0];
}
function isEmpty() {//队列判空
return this.items.length == 0;
}
function size() {//查看队列内元素个数
return this.items.length;
}
function print() {//打印队列的所有元素
return this.items;
}
使用队列:
首先我们需要初始化Queue类,然后验证一下队列是不是为空(输出是true,因为栈内没有添加元素),代码如下:
var queue = new Queue();//队列初始化
console.log(queue.isEmpty());//输出true
元素进队列,代码如下:
queue.enqueue(2);//元素进队列
queue.enqueue(3);
查看队列的对头元素,输出对列的所有元素和队列内的元素个数,代码如下:
console.log(queue.front());//输出2
console.log(queue.size());//输出2
console.log(queue.print());//输出[2,3]
队列元素出队列以及队列判空,代码如下:
queue.dequeue();
console.log(queue.size());//输出1
console.log(queue.isEmpty());//输出false
队列的应用:
1 优先队列:元素的添加和移除是基于优先级的,一个现实生活中的例子就是机场登机的顺序,头等舱和商务舱乘客的优先级要高于经济舱,甚至有些国家,老年人和孕妇(带小孩的妇女)登机时也享有优先权,还有就是医院候诊室,医生会优先处理病情比较严重的患者等等。
实现一个优先队列有这两种选项:设置优先级,然后正确的添加元素;或者用入列操作添加元素,然后按优先级移除它们,在我们的实例中会选择在正确的位置上添加元素,具体代码如下:
//优先队列方法,优先级越大,priority值越小
function priorityQueue() {
let priorityQueueItems = [];
this.elelment = element
this.enqueue = enqueue;
this.printEle = printEle;
//优先队列与默认的队列的区别是,每一个在优先队列中的元素除了元素本身还有该元素所对应的优先级
function element(name, priority) {
this.name = name;
this.priority = priority;
}
//元素进队列,除了将队列放入队列尾部,还要将该元素的优先级存储起来
function enqueue(na, pri) {
let queue_Element = new element(na, pri);
let added = false;
/*如果队列为空就直接将元素放入队列中,否则就需要比较该元素和其他元素的优先级,当找到一个比要添加
* 的元素的priority值更大(优先级更低)的项时,就把新元素插到它之前(根据这个逻辑,对于优先级相同,
* 但是先添加的元素,同意遵循先进先出的原则)
* */
for (var i = 0; i < priorityQueueItems.length; i++) {
if (queue_Element.priority < priorityQueueItems[i].priority) {
priorityQueueItems.splice(i, 0, queue_Element);
added = true;
break;
}
}
//如果要添加的元素的priority的值大于任何已有的元素,就把它添加到队列的末尾即可
if (!added) {
priorityQueueItems.push(queue_Element);
}
}
function printEle() {
return priorityQueueItems
}
}
let priority_Queue = new priorityQueue();
priority_Queue.enqueue('John', 2);
priority_Queue.enqueue('Tom', 1);
priority_Queue.enqueue('Jack', 1);
console.log(priority_Queue.printEle());
最后输出的结果如下图:
2 循环队列--击鼓传花:另一个修改版的队列实现,就是循环队列。一个简单的例子就是击鼓传花游戏,该例子中,孩子们围成一个圆圈,把花传给旁边的人。某个时刻传花停止,这个时候花在谁手里,谁就退出圆圈结束游戏,重复这个过程,直到剩下一个孩子,具体代码实现如下:
//队列应用 击鼓传花
function Queue() {
this.items = [];//保存队列中元素的数组
this.enqueue = enqueue;//进队列(从尾部进)
this.dequeue = dequeue;//出队列(从头部出)
this.size = size;//队列中的元素个数
}
function dequeue() {//出队列
return this.items.shift();
}
function enqueue(element) {//进队列
this.items.push(element);
}
function size() {//查看队列内元素个数
return this.items.length;
}
function hotPotato (nameList, num) {
let queue = new Queue();
for (let i = 0; i < nameList.length; i++ ){
queue.enqueue(nameList[i]);
}
let eliminated ='';
while (queue.size() > 1){
for (let j = 0;j <num; j++){
queue.enqueue(queue.dequeue());
}
eliminated = queue.dequeue();
console.log(eliminated + '在击鼓传花游戏中被淘汰');
}
return queue.dequeue();
}
let names = ['John','Jack','Camila','Ingrid','Carl'];
let winner = hotPotato(names,7);
console.log('The winner is'+ winner);
输出结果如下图: