队列和栈非常的类似,但是使用了不同的原则,栈是先进后出,而队列是先进先出,即遵循的是FIFO(First In First Out,先来先服务)。队列也可以这样形象地想象成是将数组装到一根管子里,一边是进口,另一边是出口。所以队列是在尾部添加新元素,并从头部移除元素,最新添加的元素必须排在队尾。在生活当中,最常见的例子就是排队。
一、创建队列
话不多说,来看看如何创建一个类来表示自己的队列。先从最基本的声明类开始:
function Queue(){
//在这里面写队列的方法、属性
}
首先,我们需要一个用于存储队列中元素的数据结构,在这里可以和栈一样,用数组来存储队列的元素。
var items = [];
接下来需要声明一些队列的方法。
enqueue(element):向队列尾部添加新的元素。
dequeue():移除队列的第一个元素,并且返回移除的元素。
front():返回队列中第一个元素,仅返回不做任何其它操作。
isEmpty():队列是否为空,为空则返回true,否则返回false。
size():返回队列中包含有几个元素。
首先要实现队列的enqueue方法,这个方法负责向队列中添加新的元素,但是一定要注意,只能添加到队尾!!!既然使用数组来存储元素,那就可以借用数组的push方法来往队列中添加元素:
this.enqueue=function(element){
items.push(element);
};
接下来要实现的是dequeue方法,这个方法负责从队列中移除元素,最先添加的元素就会被最先移除,这时候就可以想到数组的shift方法,shift方法从数组中移除存储在索引为0的元素,也就是数组中的第一个元素:
this.dequeue=function(){
return items.shift();
};
在队列中,只能使用enqueue方法和dequeue方法添加和移除元素,这样就保证了队列的FIFO原则。
接下来就可以实现一些队列的辅助方法了。如果想知道队列最前边的元素是什么,可以用front方法,这个方法返回队列最前面的项(数组索引为0):
this.front=function(){
return items[0];
};
下一个是isEmpty方法,如果队列为空就返回true,不为空则返回false:
this.isEmpty=function(){
return items.length==0;
};
再实现一下size方法:
this.size=function(){
return items.length;
};
最后来一个清空队列的方法clear:
this.clear=function(){
items=[];
};
好,到此为止一个完整的队列就完成了。
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.size=function(){
return items.length;
};
//清空队列
this.clear=function(){
items=[];
};
//打印输出
this.print=function(){
console.log(items.toString());
};
}
二、优先队列
就像我们在火车站取票的时候,服务台经常会有一个牌子写着军人或者其他比较特殊的人具有优先取票的资格。另一个现实中的例子就是医院,医生会优先处理病情比较严重的患者,这些都用到了优先队列的思想。
实现一个优先队列,有两种思想:第一个就是给入列元素先设置优先级,然后在正确的位置添加元素;第二个就是照常添加元素,出列的时候遍历队列,按照优先级别进行出列。现在来实现一下第一种思想的优先队列:
function PriorityQueue(){
var items = [];
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);
}else{
var added = false;
for(var i=0;i<items.length;i++){
if(queueElement.priority<items[i].priority){
items.splice(i,0,queuelement);
added = true;
break;
}
}
if(!added){
items.push(queueElement);
}
}
};
//其它方法和前面的Queue的实现相同
...
}
稍微读一下代码,优先队列和常规的队列的区别就是要向元素添加一个优先级别。
如果队列为空,可以将元素直接入列。否则就需要比较该元素与其他元素的优先级。当找到一个要比添加的元素优先级值大(值越大优先级越低)的项时,就把新元素插入到它之前。这里使用了splice方法,一旦找到priority值更大的元素,就插入新元素并且终止队列循环。这样队列就根据优先级排列了。如果天机的元素的priority值大于任何已有的元素,则把它加到队尾就可以了。
三、循环队列
还有一个修改版的队列实现,那就是循环队列,其实这个相对简单,只需要把第一个元素移除的同时往队列添加,并且一直往前循环,这样就实现了循环队列,这个大家可以动手实现一下。