《學習JavaScript數據結構與算法》讀書筆記。算法
隊列是遵行FIFO(First In First Out, 先進先出)原則的一組有序的項。隊列再尾部添加新元素,並從頂部移除元素。segmentfault
在現實中,最多見的隊列的例子就是排隊。設計模式
1.建立隊列數組
如今,咱們來建立一個類來表示一個隊列。先從最基本的聲明類開始:數據結構
function Queue(){ // 這裏是屬性和方法 }
首先,須要一個用戶存儲隊列中元素的數據結構,咱們可使用數組。數據結構和算法
var items = [];
接下來,聲明一些隊列可用的方法:學習
enqueue(element(s)):進隊,向隊列尾部添加一個(或多個)新項。this
dequeue():移除隊列的第一項,並返回被移除的元素。設計
front():返回隊列中第一個元素-最早被添加,也會是最早被移除的元素。(只返回,不移除)。code
isEmpty():若是隊列爲空,返回true,不然,返回false。
size():返回隊列的長度。
首先,咱們來實現enqueue的方法,這個方法負責向隊列中添加新元素。只能是添加到隊列的尾部。
this.enqueue = function(element) { items.push(element); }
接下來要實現的是dequeue方法,這個方法負責從隊列移除項。因爲隊列遵循的是先進先出原則,因此最早移除的就是最早添加的,元素是排在數組的第一位。
this.dequeue = function() { return items.shift(); }
只有enqueue方法和dequeue方法能夠添加和移除元素,這樣就確保了Queue類遵循先進先出原則。
如今來爲咱們的類實現一些額外的輔助方法:
// front():返回隊列中第一個元素 this.front = function() { return items[0]; } // isEmpty():若是隊列爲空,返回true,不然,返回false this.isEmpty = function() { return items.length === 0; } // size():返回隊列的長度 this.size = function() { return items.length; }
完成,咱們的Queue類實現好了,如今來看看Queue完整的實現是怎麼樣的:
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.clear = function() { items = []; } this.size = function() { return items.length; } this.print = function() { console.log(items.toString()); } }
2.使用Queue類
var queue = new Queue(); console.log(queue.isEmpty()); // 輸出 true queue.enqueue('John'); // 添加元素 John queue.enqueue('Jam'); // 添加元素 Jam queue.enqueue('Camila'); // 添加元素 Camila queue.print(); console.log(queue.size); // 輸出 3 console.log(queue.isEmpty); // 輸出 false queue.dequeue(); // 移除元素 queue.dequeue(); queue.print();
運行上面的代碼,咱們能夠看出,咱們已經實現了隊列,遵循了先入先出原則。
3.優先隊列
上面咱們已經實現了一個隊列,如今,逐步深刻,咱們來看看什麼是優先隊列。
優先隊列是默認隊列的變種,它的元素的添加和移除是基於優先級的。一個現實的例子就是醫院的(急診科)候診室。醫生會優先處理病情比較嚴重的患者。
實現一個優先隊列,有兩種選擇:設置優先級,而後在正確的位置添加元素;或者用默認入列操做添加元素,任何按照優先級移除它們。下面,咱們將會在正確的位置添加元素,任何用默認你的出列操做。
function PriorityQueue() { var items = []; // {1} 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); // {2} } else { var added = false; for(var i = 0; i < items.length; i++) { if(queueElement.priority < items.[i].priority) { items.splice(i, 0, queueElement); // {3} added = true; break; } } if(!added) { // {4} items.push(queueElement); } } } // 其餘方法與默認隊列同樣 }
咱們建立了一個特殊的元素(行{1}),這個元素包含了要添加到隊列的元素及其優先級。
若是隊列爲空,則直接將元素入列(行{2})。不然,就要進行比較。當找到一個比要添加的元素的priority值更大(優先級更低)時,就將元素插入到它以前(行{3})。
若是要添加的元素的priority指大於任何已有的元素,則直接將其添加到隊列的末尾(行{4})。
var priorityQueue = new PriorityQueue(); priorityQueue.enqueue('John', 2); priorityQueue.enqueue('Jam', 1); priorityQueue.enqueue('Sam', 1); priorityQueue.print();
至此,咱們已經實現了優先隊列,下面,將再介紹一種隊列——循環隊列
4.循環隊列——擊鼓傳花
循環隊列是默認隊列的另外一種修改版,什麼是循環隊列呢?舉個現實中的例子,記得小時候玩過的傳花遊戲嗎?
幾個孩子圍成一圈,開始擊鼓了,孩子就把花盡快地傳遞給旁邊的人,某一時刻鼓聲中止了,傳花也就中止了,這個時候花落在誰手上,誰就被淘汰。鼓聲響起,繼續傳花,如此循環,直至只剩下一個孩子,即勝者。
function hotPotato(namelist, num) { var queue = new Queue(); for (var i = 0; i < namelist.length; i++) { // {1} queue.enqueue(namelist[i]); } var eliminated = ""; while (queue.size() > 1) { // {2} 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); //john
首先,先把名單添加到隊列裏面(行{1})。
當隊列的的長度大於1的時候(行{2}),根據指定的一個數字(num)迭代隊列,將隊列的頭一個移除並將其添加到隊尾(行{3})。
一旦傳遞次數達到給定的數字,則刪除此時的隊列第一項(行{4}),即拿着花的那我的,他將被淘汰。
如此循環,直至隊列的長度等於1,返回勝者(行{5})。
5.小結
經過這篇文章的介紹,咱們學會了如何用數組構造出隊列的類。同時,還掌握了很著名的優先隊列、循環隊列這兩種結構。
附:
JavaScript數據結構和算法系列:
JS 棧
JavaScript設計模式系列:
JavaScript設計模式之策略模式
JavaScript設計模式之發佈-訂閱模式(觀察者模式)-Part1