第4章“隊列”
隊列是遵循FIFO(First In First Out,先進先出,也稱爲先來先服務)原則的一組有序的項。
隊列在尾部添加新元素,並從頂部移除元素。最新添加的元素必須排在隊列的末尾
常見例子就是:排隊
一.創建隊列
- 我們需要創建自己的類來表示一個隊列。先從最基本的聲明類開始:
function Queue() {
//這裏是屬性和方法
}
- 首先需要一個用於存儲隊列中元素的數據結構。我們可以使用數組,就像在上一章 Stack 類
中那樣使用(你會發現 Queue 類和 Stack 類非常類似,只是添加和移除元素的原則不同):
var items = [];
- 需要聲明一些隊列可用的方法:
enqueue(element(s)) :向隊列尾部添加一個(或多個)新的項。
dequeue() :移除隊列的第一(即排在隊列最前面的)項,並返回被移除的元素。
front() :返回隊列中第一個元素——最先被添加,也將是最先被移除的元素。隊列不
做任何變動(不移除元素,只返回元素信息——與 Stack 類的 peek 方法非常類似)。
isEmpty() :如果隊列中不包含任何元素,返回 true ,否則返回 false 。
size() :返回隊列包含的元素個數,與數組的 length 屬性類似。
- 向隊列添加新元素enqueue 。新的項只能添加到隊列末尾
由於隊列遵循先進先出原則,最先添加的項也是最先被移除的。
function Queue() {
//這裏是屬性和方法
var items = [];
// 向隊列添加新元素。新的項只能添加到隊列末尾
this.enqueue = function(element){
items.push(element);
console.log(items);Array(1)
};
}
var queue = new Queue();
queue.enqueue(3);//[3]
queue.enqueue(5);//[3,5]
- 從隊列移除項dequeue.由於隊列遵循先進先出原則,最先添加的項也是最先被移除的。
function Queue() {
//這裏是屬性和方法
var items = [];
// 向隊列添加新元素。新的項只能添加到隊列末尾
this.enqueue = function(element){
items.push(element);
console.log(items);Array(1)
};
this.dequeue = function(){
return items.shift();
};
}
var queue = new Queue();
queue.enqueue(3);//[3]
queue.enqueue(5);//[3,5]
queue.dequeue();//移除第一個元素
要想看到dequeue的移除效果可以把所有元素打印出來,
也可以看現在隊列(數組)的長度
- 只有 enqueue 方法和 dequeue 方法可以添加和移除元素, 這樣就確保了 Queue 類遵循先進先出原則
- 額外的輔助方法:front/isEmpty/size/print
返回隊列最前面的項:front
this.front = function(){
return items[0];
};
isEmpty 方法。如果隊列爲空,它會返回 true ,否則返回 false
(注意這個方法和Stack 類裏的一樣)
this.isEmpty = function(){
return items.length == 0;
};
size 方法也跟 Stack 類裏的一樣
判斷數組裏的元素個數
this.size = function(){
return items.length;
};
打印隊列中的元素和Stack 類裏的一樣
this.print = function(){
console.log(items.toString());
};
完成代碼:
<script>
function Queue() {
//這裏是屬性和方法
var items = [];
// 向隊列添加新元素。新的項只能添加到隊列末尾
this.enqueue = function(element){
items.push(element);
console.log(items);Array(1)
};
// 從隊列移除項
// 由於隊列遵循先進先出原則,最先添加的項也是最先被移除的。
this.dequeue = function(){
return items.shift();
};
// 只有 enqueue 方法和 dequeue 方法可以添加和移除元素,
// 這樣就確保了 Queue 類遵循先進先出原則
// 額外的輔助方法
// 返回隊列最前面的項
this.front = function(){
return items[0];
};
// isEmpty 方法。如果隊列爲空,它會返回 true ,否則返回 false
// (注意這個方法和Stack 類裏的一樣)
this.isEmpty = function(){
return items.length == 0;
};
// size 方法也跟 Stack 類裏的一樣
// 判斷數組裏的元素個數
this.size = function(){
return items.length;
};
// 打印隊列中的元素和Stack 類裏的一樣
this.print = function(){
console.log(items.toString());
};
}
var queue = new Queue();
queue.enqueue(3);//[3]
queue.enqueue(5);//[3,5]
// queue.dequeue();//移除第一個元素
console.log(queue.front());//3
console.log(queue.isEmpty());//false
console.log(queue.size());//2
queue.print();//3,5
</script>
- Queue 類和 Stack 類非常類似。唯一的區別是 dequeue 方法和 front 方法,這是由於先進先出和後進先出原則的不同所造成的。
- 使用 Queue 類
首先要做的是實例化我們剛剛創建的 Queue 類,然後就可以驗證它爲空(輸出爲 true ,因爲我們還沒有向隊列添加任何元素):
function Queue() {
//這裏是屬性和方法
var items = [];
this.isEmpty = function(){
return items.length == 0;
};
}
var queue = new Queue();
console.log(queue.isEmpty());//true
完整代碼:
function Queue() {
var items = [];
this.enqueue = function(element){
items.push(element);
console.log(items);
};//入隊
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.print = function(){
console.log(items.toString());
};//打印隊列
}
var queue = new Queue();//聲明隊列的實例
console.log(queue.isEmpty());//false
queue.enqueue("John");//["John"]
queue.enqueue("Jack");//(2) ["John", "Jack"]
queue.enqueue("Camila");//(3) ["John", "Jack", "Camila"]
console.log(queue.size()); //輸出3
console.log(queue.isEmpty()); //輸出false
queue.dequeue();
queue.dequeue();
queue.print();//Camila
二.優先隊列
一個現實的例子就是機場登機的順序。
頭等艙和商務艙乘客的優先級要高於經濟艙乘客。在有些國家,老年人和孕婦(或帶小孩的婦女)登機時也享有高於其他乘客的優先級
另一個現實中的例子是醫院的(急診科)候診室。
醫生會優先處理病情比較嚴重的患者。通常,護士會鑑別分類,根據患者病情的嚴重程度放號
- 實現一個優先隊列,有兩種選項:設置優先級,然後在正確的位置添加元素;或者用入列操作添加元素,然後按照優先級移除它們。
- 簡單模擬排隊
function Queue() {
var items = [];
this.enqueue = function(element){
items.push(element);
console.log(items);
};//入隊
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());
};//打印隊列
}
var queue = new Queue();
console.log("隊列是否爲空: " + queue.isEmpty());
queue.enqueue('Mr.A');
queue.enqueue('Mr.B');
queue.enqueue('Mr.C');
console.log("當前隊列:");
queue.print();
console.log("出隊的人: " + queue.dequeue());
console.log("當前隊列:");
queue.print();
console.log("清空隊列:");
queue.clear();
queue.print();
- 優先隊列自己的理解:在我們排隊,來了一位擁有VIP會員卡的朋友,插到了隊伍的最前面 。過了一會兒又來了一位擁有SVIP會員卡的朋友,插到了VIP的前面 (可能存在有優先級的隊列,優先級高的人可以查到優先級低的人前面 )
注意:優先級大小、排序由自己設定。這裏設置從小到大排序,優先級相同則先進先出
function PriorityQueue(){
var items = [];
function QueueElement(element,priority){
this.element = element;
this.priority = priority;
}
this.enqueue = function(element, priority){
var qe = new QueueElement(element, priority);
//若隊列爲空則直接將元素入列否則需要比較該元素與其他元素的優先級
if(this.isEmpty()){
items.push(qe);
}else{
var added = false;
//找出比要添加元素的優先級值更大的項目,就把新元素插入到它之前。
for(var i=0; i<items.length; i++){
//一旦找到priority值更大的元素就插入新元素並終止隊列循環
if(qe.priority < items[i].priority){
items.splice(i,0,qe);
added = true;
break;
}
}
if(!added){
items.push(qe);
}
}
};
this.isEmpty = function(){
return items.length === 0;
};
this.print = function(){
var str = '';
for(var i=0; i<items.length; i++){
str += items[i].priority + ' ' + items[i].element + '\n'
}
console.log(str.toString());
}
}
/*test*/
var pq = new PriorityQueue();
pq.enqueue('John',2);
pq.enqueue('Jack',1);
pq.enqueue('Camila',1);
pq.print();
更改以下爲“最大優先隊列”
三.循環隊列——擊鼓傳花
-
還有另一個修改版的隊列實現,就是循環隊列。
-
循環隊列的一個例子就是擊鼓傳花遊戲(Hot
Potato)。在這個遊戲中,孩子們圍成一個圓圈,把花儘快地傳遞給旁邊的人。某一時刻傳花停止,
這個時候花在誰手裏,誰就退出圓圈結束遊戲。重複這個過程,直到只剩一個孩子(勝者) -
擊鼓傳花(循環隊列)代碼:
function Queue() {
var items = [];
this.enqueue = function (ele) {
items.push(ele);
};//入隊
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 hotPotato (nameList, num){//參數:表示人的數組,傳花的頻率
var queue = new Queue(); // {1}
for (var i=0; i<nameList.length; i++){
queue.enqueue(nameList[i]); // {2}////初始化,把裏面的名字全都加入隊列,進入隊列
}
var eliminated = '';//被淘汰的人
while (queue.size() > 1){ //只要隊列至少還有兩個人,就一直循環
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);//最終剩餘一人