JavaScript數(shù)據(jù)結(jié)構(gòu)之 - 隊列

前面我們學習了棧的實現(xiàn),隊列和棧非常類似袱蜡,但是使用了不同的原則丝蹭,而非后進先出。

隊列是遵循FIFO(First In First Out坪蚁,先進先出)原則的一組有序的項奔穿。隊列在尾部添加新元素,并從頂部移除元素敏晤。最新添加的元素必須排在隊列的末尾贱田。

在計算機科學中,一個最常見的例子就是打印隊列嘴脾。比如說我們要打印五份文檔男摧。我們會打開每個文檔蔬墩,然后點擊打印按鈕。每個文檔都會被發(fā)送至打印隊列耗拓。第一個發(fā)送到打印隊列的文檔會首先被打印拇颅,以此類推,直到打印完所有文檔乔询。

二樟插、隊列的實現(xiàn)

2.1 普通隊列

創(chuàng)建普通隊列類:

// Queue類

function Queue () {

? this.items = [];

? this.enqueue = enqueue;

? this.dequeue = dequeue;

? this.front = front;

? this.isEmpty = isEmpty;

? this.size = size;

? this.clear = clear;

? this.print = print;

}

隊列里面有一些聲明的輔助方法:

enqueue(element):向隊列尾部添加新項

dequeue():移除隊列的第一項(即排在隊列最前面的項),并返回被移除的元素

front():返回隊列中第一個元素,隊列不做任何變動,和Stack的peek()方法類似

isEmpty():如果隊列中不包含任何元素败砂,返回true,否則返回false

size():返回隊列包含的元素個數(shù),與數(shù)組的length屬性類似

print():打印隊列中的元素

clear():清空整個隊列

下面我們來一一實現(xiàn)這些輔助方法:

// 向隊列尾部添加元素

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 clear () {

? this.items = [];

}

// 打印隊列里的元素

function print () {

? console.log(this.items.toString());

}

創(chuàng)建普通隊列實例進行測試:

// 創(chuàng)建Queue實例

var queue = new Queue();

console.log(queue.isEmpty());? ? // true

queue.enqueue("John");? ? ? ? ? ? // undefined

queue.enqueue("Jack");? ? ? ? ? ? // undefined

queue.enqueue("Camila");? ? ? ? ? // undefined

queue.print();? ? ? ? ? ? ? ? ? ? // "John,Jack,Camila"

console.log(queue.size());? ? ? ? // 3

console.log(queue.isEmpty());? ? // false

queue.dequeue();? ? ? ? ? ? ? ? ? // "John"

queue.dequeue();? ? ? ? ? ? ? ? ? // "Jack"

queue.print();? ? ? ? ? ? ? ? ? ? // "Camila"

queue.clear();? ? ? ? ? ? ? ? ? ? // undefined

console.log(queue.size());? ? ? ? // 0

2.2 優(yōu)先隊列

2.2.1 定義

普通隊列的添加和移除只依賴于先后順序监婶,先來的先添加,后來的后添加齿桃,然后按照先后順序依次從隊列移除惑惶。

但是,還有一種隊列叫優(yōu)先隊列短纵,元素的添加和移除是依賴優(yōu)先級的带污。

一個現(xiàn)實的例子就是機場登機的順序。頭等艙和商務艙乘客的優(yōu)先級要高于經(jīng)濟艙乘客香到。再比如火車鱼冀,老年人、孕婦和帶小孩的乘客是享有優(yōu)先檢票權(quán)的悠就。

2.2.2 分類

優(yōu)先隊列分為兩類:

最小優(yōu)先隊列

最大優(yōu)先隊列

最小優(yōu)先隊列是把優(yōu)先級的值最小的元素被放置到隊列的最前面(代表最高的優(yōu)先級)千绪。比如有四個元素:”John”, “Jack”, “Camila”, “Tom”,他們的優(yōu)先級值分別為4梗脾,3荸型,2,1炸茧。

那么最小優(yōu)先隊列排序應該為:“Tom”瑞妇,”Camila”,”Jack”梭冠,”John”辕狰。

最大優(yōu)先隊列正好相反,把優(yōu)先級值最大的元素放置在隊列的最前面控漠,以上面的為例柳琢,最大優(yōu)先隊列排序應該為:“John”, “Jack”, “Camila”, “Tom”

2.2.2 實現(xiàn)

實現(xiàn)一個優(yōu)先隊列,有兩種選項:

設置優(yōu)先級柬脸,根據(jù)優(yōu)先級正確添加元素他去,然后和普通隊列一樣正常移除

設置優(yōu)先級,和普通隊列一樣正常按順序添加倒堕,然后根據(jù)優(yōu)先級移除

這里最小優(yōu)先隊列和最大優(yōu)先隊列我都采用第一種方式實現(xiàn)灾测,大家可以嘗試一下第二種。

所以我只重寫enqueue()方法和print()方法垦巴,其他方法和上面的普通隊列完全相同媳搪。完整代碼見我的github

實現(xiàn)最小優(yōu)先隊列:

// 定義最小優(yōu)先隊列

function MinPriorityQueue () {

? this.items = [];

? this.enqueue = enqueue;

? this.dequeue = dequeue;

? this.front = front;

? this.isEmpty = isEmpty;

? this.size = size;

? this.clear = clear;

? this.print = print;

}

實現(xiàn)最小優(yōu)先隊列enqueue()方法和print()方法:

// 優(yōu)先隊列添加元素骤宣,要根據(jù)優(yōu)先級判斷在隊列中的插入順序

function enqueue (element, priority) {

? var queueElement = {

? ? element: element,

? ? priority: priority

? };

? if (this.isEmpty()) {

? ? this.items.push(queueElement);

? } else {

? ? var added = false;

? ? for (var i = 0; i < this.size(); i++) {

? ? ? if (queueElement.priority < this.items[i].priority) {

? ? ? ? this.items.splice(i, 0, queueElement);

? ? ? ? added = true;

? ? ? ? break ;

? ? ? }

? ? }

? ? if (!added) {

? ? ? this.items.push(queueElement);

? ? }

? }

}

// 打印隊列里的元素

function print () {

? var strArr = [];

? strArr = this.items.map(function (item) {

? ? return `${item.element}->${item.priority}`;

? });

? console.log(strArr.toString());

}

最小優(yōu)先隊列測試:

// 創(chuàng)建最小優(yōu)先隊列minPriorityQueue實例

var minPriorityQueue = new MinPriorityQueue();

console.log(minPriorityQueue.isEmpty());? ? // true

minPriorityQueue.enqueue("John", 1);? ? ? ? // undefined

minPriorityQueue.enqueue("Jack", 3);? ? ? ? // undefined

minPriorityQueue.enqueue("Camila", 2);? ? ? // undefined

minPriorityQueue.enqueue("Tom", 3);? ? ? ? ? // undefined

minPriorityQueue.print();? ? ? ? ? ? ? ? ? ? // "John->1,Camila->2,Jack->3,Tom->3"

console.log(minPriorityQueue.size());? ? ? ? // 4

console.log(minPriorityQueue.isEmpty());? ? // false

minPriorityQueue.dequeue();? ? ? ? ? ? ? ? ? // {element: "John", priority: 1}

minPriorityQueue.dequeue();? ? ? ? ? ? ? ? ? // {element: "Camila", priority: 2}

minPriorityQueue.print();? ? ? ? ? ? ? ? ? ? // "Jack->3,Tom->3"

minPriorityQueue.clear();? ? ? ? ? ? ? ? ? ? // undefined

console.log(minPriorityQueue.size());? ? ? ? // 0

實現(xiàn)最大優(yōu)先隊列

最大優(yōu)先隊列只要將優(yōu)先級的判斷改為大于號”>”就可以了:在此我向大家推薦一個架構(gòu)學習交流群秦爆。交流學習群號:821169538 ?里面會分享一些資深架構(gòu)師錄制的視頻錄像:有Spring,MyBatis憔披,Netty源碼分析等限,高并發(fā)、高性能芬膝、分布式望门、微服務架構(gòu)的原理,JVM性能優(yōu)化锰霜、分布式架構(gòu)等這些成為架構(gòu)師必備的知識體系筹误。還能領取免費的學習資源,目前受益良多癣缅。

// 最大優(yōu)先隊列MaxPriorityQueue類

function MaxPriorityQueue () {

? this.items = [];

? this.enqueue = enqueue;

? this.dequeue = dequeue;

? this.front = front;

? this.isEmpty = isEmpty;

? this.size = size;

? this.clear = clear;

? this.print = print;

}

// 優(yōu)先隊列添加元素厨剪,要根據(jù)優(yōu)先級判斷在隊列中的插入順序

function enqueue (element, priority) {

? var queueElement = {

? ? element: element,

? ? priority: priority

? };

? if (this.isEmpty()) {

? ? 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);

? ? }

? }

}

最大優(yōu)先隊列測試:

// 創(chuàng)建最大優(yōu)先隊列maxPriorityQueue實例

var maxPriorityQueue = new MaxPriorityQueue();

console.log(maxPriorityQueue.isEmpty());? ? // true

maxPriorityQueue.enqueue("John", 1);? ? ? ? // undefined

maxPriorityQueue.enqueue("Jack", 3);? ? ? ? // undefined

maxPriorityQueue.enqueue("Camila", 2);? ? ? // undefined

maxPriorityQueue.enqueue("Tom", 3);? ? ? ? ? // undefined

maxPriorityQueue.print();? ? ? ? ? ? ? ? ? ? // "Jack->3,Tom->3,Camila->2,John->1"

console.log(maxPriorityQueue.size());? ? ? ? // 4

console.log(maxPriorityQueue.isEmpty());? ? // false

maxPriorityQueue.dequeue();? ? ? ? ? ? ? ? ? // {element: "Jack", priority: 3}

maxPriorityQueue.dequeue();? ? ? ? ? ? ? ? ? // {element: "Tom", priority: 3}

maxPriorityQueue.print();? ? ? ? ? ? ? ? ? ? // "Camila->2,John->1"

maxPriorityQueue.clear();? ? ? ? ? ? ? ? ? ? // undefined

console.log(maxPriorityQueue.size());? ? ? ? // 0

2.3 循環(huán)隊列

還有一種隊列實現(xiàn)叫做循環(huán)隊列友存。

循環(huán)隊列的一個例子就是擊鼓傳花游戲(Hot Potato)丽惶。在這個游戲中,孩子們圍城一個圓圈爬立,擊鼓的時候把花盡快的傳遞給旁邊的人钾唬。某一時刻擊鼓停止,這時花在誰的手里侠驯,誰就退出圓圈直到游戲結(jié)束抡秆。重復這個過程,直到只剩一個孩子(勝者)吟策。

下面我們在普通隊列的基礎上儒士,實現(xiàn)一個模擬的擊鼓傳花游戲:

// 實現(xiàn)擊鼓傳花

function hotPotato (nameList, num) {

? var queue = new Queue();

? for (var i = 0; i < nameList.length; i++) {

? ? queue.enqueue(nameList[i]);

? }

? var eliminated = '';

? while (queue.size() > 1) {

? ? // 循環(huán)num次,隊首出來去到隊尾

? ? for (var i = 0; i < num; i++) {

? ? ? queue.enqueue(queue.dequeue());

}

? ? // 循環(huán)num次過后檩坚,移除當前隊首的元素

? ? eliminated = queue.dequeue();

? ? console.log(`${eliminated}在擊鼓傳花中被淘汰着撩!`);

}

? // 最后只剩一個元素

? return queue.dequeue();

}

// 測試

var nameList = ["John", "Jack", "Camila", "Ingrid", "Carl"];

var winner = hotPotato(nameList, 10);

console.log(`最后的勝利者是:${winner}`);

執(zhí)行結(jié)果為:

// John在擊鼓傳花中被淘汰诅福!

// Ingrid在擊鼓傳花中被淘汰!

// Jack在擊鼓傳花中被淘汰拖叙!

// Camila在擊鼓傳花中被淘汰氓润!

// 最后的勝利者是:Carl

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市薯鳍,隨后出現(xiàn)的幾起案子咖气,更是在濱河造成了極大的恐慌,老刑警劉巖挖滤,帶你破解...
    沈念sama閱讀 211,948評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件崩溪,死亡現(xiàn)場離奇詭異,居然都是意外死亡斩松,警方通過查閱死者的電腦和手機伶唯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來惧盹,“玉大人乳幸,你說我怎么就攤上這事×氩危” “怎么了反惕?”我有些...
    開封第一講書人閱讀 157,490評論 0 348
  • 文/不壞的土叔 我叫張陵尝艘,是天一觀的道長演侯。 經(jīng)常有香客問我,道長背亥,這世上最難降的妖魔是什么秒际? 我笑而不...
    開封第一講書人閱讀 56,521評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮狡汉,結(jié)果婚禮上娄徊,老公的妹妹穿的比我還像新娘。我一直安慰自己盾戴,他們只是感情好寄锐,可當我...
    茶點故事閱讀 65,627評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著尖啡,像睡著了一般橄仆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上衅斩,一...
    開封第一講書人閱讀 49,842評論 1 290
  • 那天盆顾,我揣著相機與錄音,去河邊找鬼畏梆。 笑死您宪,一個胖子當著我的面吹牛奈懒,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播宪巨,決...
    沈念sama閱讀 38,997評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼磷杏,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了揖铜?” 一聲冷哼從身側(cè)響起茴丰,我...
    開封第一講書人閱讀 37,741評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎天吓,沒想到半個月后贿肩,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,203評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡龄寞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,534評論 2 327
  • 正文 我和宋清朗相戀三年汰规,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片物邑。...
    茶點故事閱讀 38,673評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡溜哮,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出色解,到底是詐尸還是另有隱情茂嗓,我是刑警寧澤,帶...
    沈念sama閱讀 34,339評論 4 330
  • 正文 年R本政府宣布科阎,位于F島的核電站述吸,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏锣笨。R本人自食惡果不足惜蝌矛,卻給世界環(huán)境...
    茶點故事閱讀 39,955評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望错英。 院中可真熱鬧入撒,春花似錦、人聲如沸椭岩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,770評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽判哥。三九已至献雅,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間姨伟,已是汗流浹背惩琉。 一陣腳步聲響...
    開封第一講書人閱讀 32,000評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留夺荒,地道東北人瞒渠。 一個月前我還...
    沈念sama閱讀 46,394評論 2 360
  • 正文 我出身青樓良蒸,卻偏偏與公主長得像,于是被迫代替她去往敵國和親伍玖。 傳聞我的和親對象是個殘疾皇子嫩痰,可洞房花燭夜當晚...
    茶點故事閱讀 43,562評論 2 349

推薦閱讀更多精彩內(nèi)容