JS中隊(duì)列和雙端隊(duì)列實(shí)現(xiàn)及應(yīng)用詳解
隊(duì)列
- 隊(duì)列
- 雙端隊(duì)列數(shù)據(jù)結(jié)構(gòu)
- 應(yīng)用
- 用擊鼓傳花游戲模擬循環(huán)隊(duì)列
- 用雙端對(duì)列檢查一個(gè)詞是否構(gòu)成回文
- 生成 1 到 n 的二進(jìn)制數(shù)
隊(duì)列和雙端隊(duì)列
隊(duì)列遵循先進(jìn)后出(FIFO, 也稱(chēng)為先來(lái)先服務(wù)) 原則的. 日常有很多這樣場(chǎng)景: 排隊(duì)購(gòu)票、銀行排隊(duì)等.
由對(duì)列的特性,銀行排隊(duì)為例, 隊(duì)列應(yīng)該包含如下基本操作:
- 加入隊(duì)列(取號(hào)) enqueue
- 從隊(duì)列中移除(辦理業(yè)務(wù)離開(kāi)) dequeue
- 當(dāng)前排隊(duì)號(hào)碼(呼叫下一個(gè)人) peek
- 當(dāng)前隊(duì)列長(zhǎng)度(當(dāng)前排隊(duì)人數(shù)) size
- 判斷隊(duì)列是不是空 isEmpty
class Queue { constructor() { // 隊(duì)列長(zhǎng)度, 類(lèi)數(shù)組 length this.count = 0 // 隊(duì)列中所有項(xiàng) this.items = {} // 記錄對(duì)列頭, 類(lèi)數(shù)組 index this.lowestCount = 0 } enqueue(ele) { this.items[this.count++] = ele } dequeue() { if (this.isEnpty()) { return undefined } const ele = this.items[this.lowestCount] delete this.items[this.lowestCount] this.lowestCount++ return ele } peek() { if (this.isEnpty()) { return } return this.items[this.lowestCount] } size() { /** * 當(dāng)隊(duì)列為非空時(shí): * 1. count 是長(zhǎng)度 * 2. lowestCount 是下標(biāo) * 兩者關(guān)系應(yīng)該 lowestCount = count - 1 */ return this.count - this.lowestCount } isEnpty() { return this.size() == 0 } clear() { this.items = {} this.lowestCount = 0 this.count = 0 } toString() { if (this.isEnpty()) { return '' } let objString = `${this.items[this.lowestCount]}` for (let i = this.lowestCount + 1; i < this.count; i++) { objString = `${objString}, ${this.items[i]}` } return objString } }
雙端隊(duì)列(deque 或 double-ended queue)
什么是雙端隊(duì)列?
允許從前端(front)和后端(rear)添加元素, 遵循的原則先進(jìn)先出或后進(jìn)先出.
雙端隊(duì)列可以理解為就是棧(后進(jìn)先出)和隊(duì)列(先進(jìn)先出)的一種結(jié)合體. 既然是結(jié)合那么相應(yīng)的操作也支持隊(duì)列,棧的操作. 下面我們定義一個(gè)Deque
- addFront
- removeFront
- addBack
- removeBack
- clear
- isEmpty
- peekFront
- prekBack
- size
- toString
- class Deque {
constructor() { this.items = {} this.count = 0 this.lowestCount = 0 } addFront(ele) { if (this.isEmpty()) { this.items[this.count] = ele } else if (this.lowestCount > 0) { this.lowestCount -= 1 this.items[this.lowestCount] = ele } else { for (let i = this.count; i > 0; i--) { this.items[i] = this.items[i - 1] } this.items[0] = ele } this.count++ return ele } removeFront() { if (this.isEmpty()) { return } const delEle = this.items[this.lowestCount] delete this.items[this.lowestCount] this.lowestCount++ return delEle } addBack(ele) { this.items[this.count] = ele this.count++ } removeBack() { if (this.isEmpty()) { return } const delEle = this.items[this.count - 1] delete this.items[this.count - 1] this.count-- return delEle } peekFront() { if (this.isEmpty()) { return } return this.items[this.lowestCount] } peekBack() { if (this.isEmpty()) { return } return this.items[this.count - 1] } size() { return this.count - this.lowestCount } isEmpty() { return this.size() === 0 } clear() { this.items = {} this.count = 0 this.lowestCount = 0 } toString() { if (this.isEmpty()) { return '' } let objString = `${this.items[this.lowestCount]}` for (let i = this.lowestCount + 1; i < this.count; i++){ objString = `${objString}, ${this.items[i]}` } return objString } }
隊(duì)列的應(yīng)用
擊鼓傳花游戲
擊鼓傳花游戲: 簡(jiǎn)單描述就是一群人圍成一個(gè)圈傳遞花,喊停的時(shí)花在誰(shuí)手上就將被淘汰(每個(gè)人都可能在前端,每個(gè)參與者在隊(duì)列位置會(huì)不斷變化),最后只剩下一個(gè)時(shí)就是贏者. 更加詳細(xì)可以自行查閱.
下面通過(guò)代碼實(shí)現(xiàn):
function hotPotato(elementsList, num) { // 創(chuàng)建一個(gè)容器 const queue = new Queue() const elimitatedList = [] // 把元素(參賽者)加入隊(duì)列中 for (let i = 0, len = elementsList.length; i < len; i++) { queue.enqueue(elementsList[i]) } /** * 擊鼓傳花 * 首先隊(duì)列規(guī)則: 先進(jìn)先出 * 那么在傳花過(guò)程中,任何一個(gè)元素都可能是前端, 在傳花的過(guò)程中應(yīng)該就是前端位置不斷變化. * 當(dāng)喊停的時(shí)(num 循環(huán)完), 也就是花落在誰(shuí)手(誰(shuí)在前端)則會(huì)被淘汰*(移除隊(duì)列) */ while (queue.size() > 1) { for (let j = 0; j < num; j++) { queue.enqueue(queue.dequeue()) } elimitatedList.push(queue.dequeue()) } return { winer: queue.dequeue(), elimitatedList } }
代碼運(yùn)行如下:
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] console.log(hotPotato(arr, Math.ceil(Math.random() * 10))) // { winer: 5, elimitatedList: [4, 8, 2, 7, 3,10, 9, 1, 6]} console.log(hotPotato(arr, Math.ceil(Math.random() * 10))) // { winer: 5, elimitatedList: [4, 8, 2, 7, 3,10, 9, 1, 6]} console.log(hotPotato(arr, Math.ceil(Math.random() * 10))) // { winer: 8, elimitatedList: [10, 1, 3, 6, 2,9, 5, 7, 4]}
判斷回文
上一篇棧中也有涉及回文的實(shí)現(xiàn), 下面我們通過(guò)雙端隊(duì)列來(lái)實(shí)現(xiàn)同樣的功能.
function palindromeChecker(aString) { if (!aString || typeof aString !== 'string' || !aString.trim().length) { return false } const deque = new Deque() const lowerString = aString.toLowerCase().split(' ').join('') // 加入隊(duì)列 for (let i = 0; i < lowerString.length; i++) { deque.addBack(lowerString[i]) } let isEqual = true let firstChar = '' let lastChar = '' while (deque.size() > 1 && isEqual) { firstChar = deque.removeFront() lastChar = deque.removeBack() if (firstChar != lastChar) { isEqual = false } } return isEqual }
下面通過(guò)代碼演示下:
console.log(palindromeChecker('abcba')) // true 當(dāng)前為回文
生成 1 到 n 的二進(jìn)制數(shù)
function generatePrintBinary(n) { var q = new Queue() q.enqueue('1') while (n-- > 0) { var s1 = q.peek() q.dequeue() console.log(s1) var s2 = s1 q.enqueue(s1 + '0') q.enqueue(s2 + '1') } } generatePrintBinary(5) // => 1 10 11 100 101
到此這篇關(guān)于JS中隊(duì)列和雙端隊(duì)列實(shí)現(xiàn)及應(yīng)用詳解的文章就介紹到這了,更多相關(guān)JS 雙端隊(duì)列 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- js下寫(xiě)一個(gè)事件隊(duì)列操作函數(shù)
- JavaScript隊(duì)列函數(shù)和異步執(zhí)行詳解
- javascript中利用數(shù)組實(shí)現(xiàn)的循環(huán)隊(duì)列代碼
- JS實(shí)現(xiàn)隊(duì)列的先進(jìn)先出功能示例
- JS實(shí)現(xiàn)利用兩個(gè)隊(duì)列表示一個(gè)棧的方法
- JavaScript數(shù)組實(shí)現(xiàn)數(shù)據(jù)結(jié)構(gòu)中的隊(duì)列與堆棧
- 自己封裝的javascript事件隊(duì)列函數(shù)版
- JavaScript 異步方法隊(duì)列鏈實(shí)現(xiàn)代碼分析
- NodeJs入門(mén)教程之定時(shí)器和隊(duì)列
- JS中的算法與數(shù)據(jù)結(jié)構(gòu)之隊(duì)列(Queue)實(shí)例詳解
相關(guān)文章
JS實(shí)現(xiàn)逐頁(yè)將PDF文件轉(zhuǎn)為圖片格式
這篇文章主要為大家分享了如何通過(guò)前端js將pdf文件轉(zhuǎn)為圖片格式,并且支持翻頁(yè)預(yù)覽、以及圖片打包下載,文中的示例代碼簡(jiǎn)潔易懂,需要的可以參考一下2023-05-05js與css實(shí)現(xiàn)彈出層覆蓋整個(gè)頁(yè)面的方法
這篇文章主要介紹了js與css實(shí)現(xiàn)彈出層覆蓋整個(gè)頁(yè)面的方法,分別以實(shí)例形式展示了彈出層覆蓋整個(gè)頁(yè)面的css樣式與js控制的實(shí)現(xiàn)技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2014-12-12JS 新增Cookie 取cookie值 刪除cookie 舉例詳解
cookie很實(shí)用的一個(gè)功能,可以判斷某個(gè)狀態(tài),下面與大家分享下JS 如何新增Cookie 取cookie值 刪除cookie,感興趣的朋友可以參考下2014-10-10用js一次改變多個(gè)input的readonly屬性值的方法
這篇文章主要介紹了用js一次改變多個(gè)input的readonly屬性值的方法,需要的朋友可以參考下2014-06-06javascript強(qiáng)制點(diǎn)擊廣告的方法
這篇文章主要介紹了javascript強(qiáng)制點(diǎn)擊廣告的方法,可用于下載站或文檔顯示站,實(shí)現(xiàn)點(diǎn)擊后才能出現(xiàn)相應(yīng)顯示的功能,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-02-02es6數(shù)組之?dāng)U展運(yùn)算符操作實(shí)例分析
這篇文章主要介紹了es6數(shù)組之?dāng)U展運(yùn)算符操作,結(jié)合實(shí)例形式總結(jié)分析es6數(shù)組擴(kuò)展運(yùn)算符具體原理、實(shí)現(xiàn)方法及操作注意事項(xiàng),需要的朋友可以參考下2020-04-04js+css實(shí)現(xiàn)的簡(jiǎn)單易用兼容好的分頁(yè)
使用html、js、css實(shí)現(xiàn)的簡(jiǎn)單易用兼容好的分頁(yè),具體的實(shí)現(xiàn)如下,感興趣的朋友可以參考下2013-12-12基于HTML5上使用iScroll實(shí)現(xiàn)下拉刷新,上拉加載更多
本文主要介紹在HTML5中使用iScroll實(shí)現(xiàn)下拉刷新,上拉加載更多數(shù)據(jù)的方法,主要就是寫(xiě)了兩個(gè)自定義函數(shù)pullDownAction和pullUpAction,分別在下拉和上拉的事件中調(diào)用他們。2016-05-05JavaScript trim 去除字符串空格的三種方法(附代碼詳解)
個(gè)人認(rèn)為最好的方法.采用的是正則表達(dá)式,這是最核心的原理.因?yàn)榭崭裼卸喾N形式。2010-05-05