[ JavaScript ] 數據結構與算法 —— 隊列

前言

JavaScript是當下最流行的編程語言之一,它可以做很多事情:

  • 數據可視化(D3.js,Three.js,Chart.js);
  • 移動端應用(React Native,Weex,AppCan,Flutter,Hybrid App,小程序);
  • 服務端(Express.js,Koa2);
  • 桌面應用(Electron,nw.js);
  • 遊戲,VR,AR(LayaAir,Egret,Turbulenz,PlayCanvas);
  • 等等。。。

而且目前大部分編程語言的高級應用都會用到數據結構與算法以及設計模式。

本篇主要有三部分

  • 什麼是隊列
  • 隊列的實現
  • 隊列的變種

什麼是隊列

較官方解釋

隊列是遵循FIFO(First In First Out,先進先出,也稱爲先來先服務)原則的一組有序的項。
隊列在尾部添加新元素,並從頂部移除元素。最新添加的元素必須排在隊列的末尾 。

隊列.png
注:出隊入隊是自己加的,不知道是不是這麼叫

個人理解

我看有很多文檔都是說隊列就像買什麼東西排隊,我認爲這個比喻用在標準隊列上不恰當。

我覺得標準隊列像是一段管道,每次都只能放一個球進去,上邊只用來放球(入隊),由於地球引力,球會從下邊的口出去(出隊)。

隊列1.png

隊列:這段可以放球的管道就是隊列
元素:管道里的球
隊首:在當前管道里的球最早放進去的那個球的位置,同時也是第一個掉出去的球
隊尾:在當前管道里的球最後放進去的那個球的位置,同時也是最後一個掉出去的球

隊列的實現

  • 添加隊列成員
  • 刪除隊列成員
  • 返回隊首的成員
  • 隊列是否爲空
  • 清空隊列
  • 隊列長度
  • 返回字符串形式的隊列成員
class Queue {
    constructor() {
        this.count = 0; // 整個隊列下一成員的位置
        this.lowestCount = 0; // 在第一位的成員位置
        this.items = {}; // 用來存放的隊列
    }

    enqueue(element) { 
        // 添加隊列成員 進入隊列
    }

    dequeue() { 
        // 刪除隊列成員 離開隊列
    }

    peek() { 
        // 返回隊首的成員
    }

    isEmpty() { 
        // 判斷隊列是否爲空
    }

    clear() { 
        // 將所有的數據初始化
    }

    size() { 
        // 隊列長度 
    }

    toString() {
        // 返回字符串形式的隊列成員
    }
}

添加隊列成員

enqueue(element) {
    this.items[this.count] = element; // 將元素放入隊列
    this.count++; // 將計數器加一
}

刪除隊列成員

dequeue() {
    if (this.isEmpty()) { // 如果是空 
        return undefined; // 返回未定義 undefined
    }
    const result = this.items[this.lowestCount]; // 將隊首的成員保存下
    delete this.items[this.lowestCount]; // 將隊首的成員刪除掉 刪除對象屬性
    this.lowestCount++; // 將隊列提前一位 指向隊首的指針後移一位
    return result; // 返回被刪除的成員
}

返回隊首的成員

peek() {
    if (this.isEmpty()) { // 非空才能繼續處理
        return undefined;
    }
    return this.items[this.lowestCount];
}

隊列是否爲空

isEmpty() { // 判斷長度是不是 0 
    return this.size() === 0;
}

清空隊列

clear() {
    this.count = 0; // 恢復初始值 
    this.lowestCount = 0;  // 恢復初始值
    this.items = {};  // 重新賦值空對象
}

隊列長度

size() { // 隊列長度 等於 整個隊列下一成員的位置 減去 在第一位的成員位置
    return this.count - this.lowestCount;
}

返回字符串形式的隊列成員

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;
}

隊列的變種

  • 優先隊列

類似去醫院看病,急診,會優先一般的門診

  • 循環隊列

類似搶凳子游戲,隊列首位相連

優先隊列

在添加成員時會判斷優先級,

class QueueElement (element, priority){ // 隊列成員類
    this.element = element; // 存放成員
    this.priority = priority;  // 存放優先級 
} 

enqueue(element, priority){ 
    let queueElement = new QueueElement(element, priority);  // 添加成員
    let added = false;  // 是否已添加到隊列
    for (let i = 0; i < this.size(); i++){  // 遍歷隊列
        if (queueElement.priority < items[i].priority){ // 尋找優先級低的成員,並插入到其之前
        // splice start
            for(let j = this.size(); j > i; j--){
                items[j] = items[j-1];
            }
            items[i] = queueElement;
        // splice end
            added = true;  // 標識符置爲真,表示已經添加
            break; // 跳出循環
        } 
    } 
    if (!added){  // 如果沒有找到優先級比新添加的成員低的,那麼將其添加到隊尾
        items.push(queueElement);
    } 
}; 

循環隊列

在操作時每刪除一個隊列成員就將刪除的這個隊列成員重新添加到隊列中

for (let i = 0; i < number; i++){ 
    queue.enqueue(queue.dequeue());
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章