JavaScript數據結構之 - 隊列

前面咱們學習了棧的實現,隊列和棧很是相似,可是使用了不一樣的原則,而非後進先出。git

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

在計算機科學中,一個最多見的例子就是打印隊列。好比說咱們要打印五份文檔。咱們會打開每一個文檔,而後點擊打印按鈕。每一個文檔都會被髮送至打印隊列。第一個發送到打印隊列的文檔會首先被打印,以此類推,直到打印完全部文檔。segmentfault

2、隊列的實現數組

2.1 普通隊列性能優化

建立普通隊列類:架構

// 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():返回隊列包含的元素個數,與數組的length屬性相似

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

clear():清空整個隊列

下面咱們來一一實現這些輔助方法:

// 向隊列尾部添加元素

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

}

建立普通隊列實例進行測試:

// 建立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 優先隊列

2.2.1 定義

普通隊列的添加和移除只依賴於前後順序,先來的先添加,後來的後添加,而後按照前後順序依次從隊列移除。

可是,還有一種隊列叫優先隊列,元素的添加和移除是依賴優先級的。

一個現實的例子就是機場登機的順序。頭等艙和商務艙乘客的優先級要高於經濟艙乘客。再好比火車,老年人、孕婦和帶小孩的乘客是享有優先檢票權的。

2.2.2 分類

優先隊列分爲兩類:

最小優先隊列

最大優先隊列

最小優先隊列是把優先級的值最小的元素被放置到隊列的最前面(表明最高的優先級)。好比有四個元素:」John」, 「Jack」, 「Camila」, 「Tom」,他們的優先級值分別爲4,3,2,1。

那麼最小優先隊列排序應該爲:「Tom」,」Camila」,」Jack」,」John」

最大優先隊列正好相反,把優先級值最大的元素放置在隊列的最前面,以上面的爲例,最大優先隊列排序應該爲:「John」, 「Jack」, 「Camila」, 「Tom」

2.2.2 實現

實現一個優先隊列,有兩種選項:

設置優先級,根據優先級正確添加元素,而後和普通隊列同樣正常移除

設置優先級,和普通隊列同樣正常按順序添加,而後根據優先級移除

這裏最小優先隊列和最大優先隊列我都採用第一種方式實現,你們能夠嘗試一下第二種。

因此我只重寫enqueue()方法和print()方法,其餘方法和上面的普通隊列徹底相同。完整代碼見個人github

實現最小優先隊列:

// 定義最小優先隊列

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;

}

實現最小優先隊列enqueue()方法和print()方法:

// 優先隊列添加元素,要根據優先級判斷在隊列中的插入順序

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

}

最小優先隊列測試:

// 建立最小優先隊列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

實現最大優先隊列

最大優先隊列只要將優先級的判斷改成大於號」>」就能夠了:在此我向你們推薦一個架構學習交流羣。交流學習羣號:821169538  裏面會分享一些資深架構師錄製的視頻錄像:有Spring,MyBatis,Netty源碼分析,高併發、高性能、分佈式、微服務架構的原理,JVM性能優化、分佈式架構等這些成爲架構師必備的知識體系。還能領取免費的學習資源,目前受益良多。

// 最大優先隊列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;

}

// 優先隊列添加元素,要根據優先級判斷在隊列中的插入順序

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

    }

  }

}

最大優先隊列測試:

// 建立最大優先隊列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 循環隊列

還有一種隊列實現叫作循環隊列

循環隊列的一個例子就是擊鼓傳花遊戲(Hot Potato)。在這個遊戲中,孩子們圍城一個圓圈,擊鼓的時候把花盡快的傳遞給旁邊的人。某一時刻擊鼓中止,這時花在誰的手裏,誰就退出圓圈直到遊戲結束。重複這個過程,直到只剩一個孩子(勝者)。

下面咱們在普通隊列的基礎上,實現一個模擬的擊鼓傳花遊戲:

// 實現擊鼓傳花

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

    // 循環num次,隊首出來去到隊尾

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

      queue.enqueue(queue.dequeue());

}

    // 循環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}`);

執行結果爲:

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

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

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

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

// 最後的勝利者是:Carl

相關文章
相關標籤/搜索