目录
1、队列是个啥?
队列(Queue),它是一种受限的线性表,先进先出(FIFO First In First Out),受限之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作。FIFO(First In First Out)标识先进队的元素,第一个出队,类似于电影院的取票口,先到的人先取票。向一个队列插入新元素又称作进队、入队,它是把新元素放到队列的末尾,使之成为新的队尾元素;从一个队列删除元素又称作出队,它是把队首元素删除掉,使其相邻的元素成为新的队首元素。示意图如下:
2、队列的常见操作
方法 | 说明 |
enqueue() | 向队列尾部添加一个(或多个)新的项 |
dequeue() | 移除队列的第一(即排在队列最前面的)项,并返回被移除的元素 |
front() | 返回队列中第一个元素,也将是最先被移除的元素 |
isEmpty() | 如果队列中不包含任何元素,返回true,否则返回false |
size() | 返回队列包含的元素个数,与数组的length属性类似 |
toString() | 将队列中的内容,转成字符串形式 |
3、封装队列结构
基于数组的方式实现栈结构,在封装的 Queue() 类的原型上添加队列的一些方法。
function Queue() { // 封装队列类
var items = [];
// 队列操作的方法
//1.将元素加入到队列中
Queue.prototype.enqueue = function(element){
this.items.push(element);
}
//2.从队列中删除前端元素
Queue.prototype.dequeue = function () {
return this.items.shift();
}
//3.查看队列前端的元素
Queue.prototype.front = function () {
return this.items[0];
}
//4.查看队列是否为空
Queue.prototype.isEmpty = function () {
return this.items.length == 0;
}
//5.查看队列中元素的个数
Queue.prototype.size = function () {
return this.items.length;
}
//6.查看队列中元素的个数
Queue.prototype.toString = function(){
var resultString = '';
for(var i in this.items){
resultString += this.items[i] + '-'
}
return resultString;
}
}
4、队列的使用
基于刚才封装的队列,进行一些队列的基本操作。
// 创建队列对象
var queue = new Queue();
// 在队列中添加元素
queue.enqueue("abc");
queue.enqueue("bcd");
queue.enqueue("cde");
// 查看一下队列前端元素
alert(queue.front()); //abc
// 查看队列是否为空和元素个数
alert(queue.isEmpty()); //false
alert(queue.size()); //3
// 从队列中删除元素
alert(queue.dequeue()); //abc
alert(queue.dequeue()); //bcd
alert(queue.dequeue()); //cde
5、队列结构的应用 — 击鼓传花算法
游戏规则:几个朋友围成一圈,开始数数,数到某个数字的人自动淘汰,然后从下一个人继续进行同样的规则,最后剩下的这个人会获得胜利,请问最后剩下的是原来在哪一个位置上的人?
(1)主要原理:创建一个队列,将所有人放入队列中,然后通过循环将队列中的每个元素出队,如果这个元素不是第 num 个数,则再将其入队,重复循环,直至队列剩下一个元素时,将其输出,这就是最终获胜的人。
(2)代码实现:
// 实现击鼓传花的函数
function passGame(nameList, num) {
// 1.创建一个队列,并且将所有的人放在队列中
var queue = new Queue();
//2.通过for循环,将nameList中的人放在队列中
for (var i=0; i <nameList.length; i++) {
queue.enqueue(nameList[i]);
}
//3.寻找最后剩下的人
while (queue.size() > 1) {
// 将前num-1中的人, 都从队列的前端取出放在队列的后端
for (var i=0; i <num-1; i++) {
queue.enqueue(queue.dequeue());
}
// 将第num个人, 从队列中移除
queue.dequeue();
}
//4.获取剩下的一个人
alert(queue.size()); //1
var endName = queue.dequeue();
alert("最终留下来的人:" + endName);
// 4.获取该人在队列中的位置
return nameList.indexOf(endName);
}
// 验证结果
var names = ['AAA','BBB','CCC','DDD','EEE'];
var index = passGame(names, 7); //数到8的人淘汰
alert("最终位置:" + index);
6、队列结构的应用 — 优先级队列
(1)优先级队列的特点:普通的队列插入一个元素,数据会被放在后端,并且需要前面所有的元素都处理完成后才会处理当前的数据。但是优先级队列,在插入一个元素的时候会考虑该数据的优先级,在插入之前,先和其他数据优先级进行比较,比较完成后,可以得出这个元素在队列中正确的位置。
是不是不太好理解,生活中有优先级队列的例子,比如老年人和孕妇(或带小孩的妇女)坐车时享有高于其他乘客的优先级,再比如头等舱和商务舱乘客的优先级要高于经济舱乘客。
(2)代码实现:
//封装优先级队列
function PriorityQueue(){
//在PriorityQueue内部重新创建一个类,可以理解成内部类
function QueueElement(element,priority){
this.element = element;
this.priority = priority;
}
//封装属性
this.items = [];
//1.比较元素的有限度,并将其入队到相应的位置
PriorityQueue.prototype.enqueue = function(element,priority){
//1.创建QueueElement对象
var queueElement = new QueueElement(element,priority);
//2.判断队列是否为空
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)
}
}
}
//2.从队列中删除前端元素
PriorityQueue.prototype.dequeue = function () {
return this.items.shift();
}
//3.查看队列前端的元素
PriorityQueue.prototype.front = function () {
return this.items[0];
}
//4.查看队列是否为空
PriorityQueue.prototype.isEmpty = function () {
return this.items.length == 0;
}
//5.查看队列中元素的个数
PriorityQueue.prototype.size = function () {
return this.items.length;
}
//6.查看队列中元素
PriorityQueue.prototype.toString = function(){
var resultString = '';
for(var i in this.items){
resultString += this.items[i].element + '-' + this.items[i].priority + '-'
}
return resultString;
}
}
(3)测试代码:
//测试代码
var pq = new PriorityQueue();
pq.enqueue('abc','111');
pq.enqueue('bcd','115');
pq.enqueue('cde','110');
alert(pq); //cde-110-abc-111-bcd-115-