1. 程式人生 > >Javascript資料結構與演算法--佇列(順序佇列、優先佇列、迴圈佇列)的實現與用法

Javascript資料結構與演算法--佇列(順序佇列、優先佇列、迴圈佇列)的實現與用法

前言

佇列和棧非常類似,前面已經講過了棧的實現與用法,現在我們來說說佇列。

佇列介紹

佇列遵循FIFO(First In First Out,先進先出)原則的一組有序的項。

佇列是一種特殊的線性表,特殊之處在於它只允許在表的前端(front)進行刪除操作,而在表的後端(rear)進行插入操作,和棧一樣,佇列是一種操作受限制的線性表。進行插入操作的端稱為隊尾,進行刪除操作的端稱為隊頭。

佇列有順序佇列,還有其他修改版本的佇列,比如:優先佇列、迴圈佇列。

順序佇列

順序佇列是佇列的順序儲存結構,它是運算受限制的順序表(線性表)。建立順序佇列結構必須為其靜態分配或動態申請一片連續的儲存空間,並設定兩個指標進行管理。一個是隊頭指標front,它指向隊頭元素;另一個是隊尾指標rear,它指向下一個入隊元素的儲存位置,如圖所示。

順序佇列

生活中,各種排隊現象。例如:排隊買票,新來的人,排在隊尾,相當於新增操作。隊頭的人先買票,買完票離開佇列,相當於刪除操作。而新增的操作卻只能在佇列的尾部進行,因此新來的人就只能排在佇列的最後。

建立佇列

佇列中的元素,可以使用連結串列儲存,也可以使用陣列儲存。我們使用陣列來儲存佇列中的元素。


/**

 * 佇列

 * 我們使用陣列來儲存佇列中的元素

 * 

 *=====佇列的入隊、出隊示意圖========

 *

 * 出隊 ----------------- 入隊

 * <--- A1,A2,A3,...,An <---

 * -----------------

 *

 *================================

*/

export default class Queue {

  constructor() {

    this.items = [];

  }

  /**

   * 向隊尾新增一個(或多個)新的元素

   * @param {*} element 新元素

   */

  enqueue(element) {

    this.items.push(element)

  }

  /**

   * 移除佇列的第一(即排在佇列最前面的)項,並返回被移除的元素

   */

  dequeue() {

    // 根據佇列的先進先出原則,使用shift方法

    // shift方法會從陣列中移除儲存在索引為0的元素

    return this.items.shift()

  }

  /**

   * 返回佇列中的第一個元素--最先被新增,也將是最先被移除的元素。

   * 佇列不做任何變動(不移除元素,只返回元素資訊)

   */
  front() {

    return this.items[0]

  }



  /**

   * 清除佇列中的所有元素

   */

  clear() {

    this.items = []

  }


  /**

   * 如果佇列中不包含任何元素,返回true,否則返回false

   */

  isEmpty() {

    return this.items.length === 0

  }


  /**

   * 返回佇列包含的元素個數,與陣列length屬性類似

   */

  size() {

    return this.items.length

  }


  /**

   * 佇列內容字串化

   */

  toString() {

    return this.items.toString()

  }

}

順序佇列應用

印表機,有一個列印佇列,誰先進入佇列,誰就先列印。


/**

 * 列印佇列的內容

 * @param {Array} queueArr 需要列印的陣列

 */

function print(queueArr) {

  let queue = new Queue()

  let s = ''

  /**

   * 檢查引數型別是否為陣列

   */

  if (queueArr instanceof Array) {

    /**

     * 將需要列印內容新增到佇列

     */

    for (let i = 0; i < queueArr.length; i++) {

      queue.enqueue(queueArr[i])

    }



    /**

     * 將隊頭的資料取出

     */

    while (!queue.isEmpty()) {

      s += queue.dequeue() + ', '

    }

    s = s.substr(0, s.length - 2)

  }

  return s;

}

優先佇列

佇列有順序佇列,還有其他修改版本的佇列,比如:迴圈佇列、優先佇列

優先佇列是順序佇列的修改版本,元素的新增和移除是基於優先順序的。一個現例項子是,在銀行排隊辦業務的順序。VIP客戶的優先順序要高於普通客戶的。另一個例子是醫院的急診科候診室。醫生會優先處理病情比較嚴重的患者。通常,護士會鑑別分類,根據患者病情的嚴重程度放號。

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

  1. 設定優先順序,然後在正確的位置新增元素。(優先新增,正常出隊)

  2. 用入列操作新增元素,然後按照優先順序移除它們。(正常新增,優先出隊)

優先佇列的實現

我們在這裡將會使用第一種方式,在正確的位置新增元素,因此可以對它們使用預設的出列操作。

queueElement.js 檔案


// queueElement.js

/**

 * 優先佇列中的元素,包含元素和優先順序

 */

export default class QueueElement {

  /**

   * 

   * @param {*} element 佇列的元素

   * @param {*} priority 優先順序

   */

  constructor(element, priority) {

    this.element = element

    this.priority = priority

  }

}

priorityQueue.js檔案


// priorityQueue.js

import QueueElement from "./queueElement";



/**

 * 最小優先佇列

 */

export default class PriorityQueue {

  constructor() {

    this.items = []

  }

  /**

   * 在正確的位置新增元素

   * @param {*} element 要新增的元素

   * @param {Int32Array} priority 優先順序

   */

  enqueue(element, priority) {

    let queueElement = new QueueElement(element, priority)

    let added = false

    for (let 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)

    }

  }



  /**

   * 列印佇列中的元素(包含優先順序)

   */

  print() {

    for (let i = 0; i < this.items.length; i++) {

      console.log(`${i + 1} - ${this.items[i].element} - ${this.items[i].priority}`)

    }

  }

  /**

   * 移除佇列的第一(即排在佇列最前面的)項,並返回被移除的元素

   */

  dequeue() {

    // 根據佇列的先進先出原則,使用shift方法

    // shift方法會從陣列中移除儲存在索引為0的元素

    return this.items.shift()

  }



  /**

   * 返回佇列中的第一個元素--最先被新增,也將是最先被移除的元素。

   * 佇列不做任何變動(不移除元素,只返回元素資訊)

   */

  front() {

    return this.items[0]

  }



  /**

   * 清除佇列中的所有元素

   */

  clear() {

    this.items = []

  }



  /**

   * 如果佇列中不包含任何元素,返回true,否則返回false

   */

  isEmpty() {

    return this.items.length === 0

  }



  /**

   * 返回佇列包含的元素個數,與陣列length屬性類似

   */

  size() {

    return this.items.length

  }



  /**

   * 佇列內容字串化

   */

  toString() {

    return this.items.toString()

  }



}

優先佇列的應用


    let priorityQueue = new PriorityQueue()

    priorityQueue.enqueue('wei', 2)

    priorityQueue.enqueue('qin', 3)

    priorityQueue.enqueue('world', 1)

    priorityQueue.enqueue('china', 1)

    priorityQueue.print()

輸出結果


1 - wei - 1

2 - world - 1

3 - china - 1

4 - qin - 2

迴圈佇列

迴圈佇列的一個例子就是擊鼓傳花的遊戲。在這個遊戲中,孩子們圍成一個圓圈,把花盡快的傳遞給旁邊的人。某一時刻傳花停止,這個時候花在誰手裡,誰就退出圓圈結束遊戲。重複這個過程,直到只剩一個孩子(勝者)。
另一個類似的案例是,約瑟夫環問題

下面,我們以擊鼓傳花遊戲來分析。

import Queue from "./queue-array";

export default class CircleQueue {

  constructor() {}

  hotPotato(nameList, num) {
    // 利用順序佇列建立的佇列,來完成迴圈佇列
    let queue = new Queue()

    for (let i = 0; i < nameList.length; i++) {
      queue.enqueue(nameList[i])
    }

    let eliminated = '';
    while (queue.size() > 1) {
      // 此過程將佇列變成迴圈佇列
      for (let i = 0; i < num; i++) {
        queue.enqueue(queue.dequeue());
      }
      eliminated = queue.dequeue();
      console.log(eliminated + '在擊鼓傳花遊戲中被淘汰')
    }
    // 返回最後勝利者
    return queue.dequeue()

  }

}

以上所有的佇列,都是在陣列結構的基礎上建立和應用的。
[完]

相關推薦

JavaScript資料結構演算法

前言 在過去的幾年中,得益於Node.js的興起,JavaScript越來越廣泛地用於伺服器端程式設計。鑑於JavaScript語言已經走出了瀏覽器,程式設計師發現他們需要更多傳統語言(比如C++和Java)提供的工具。這些工具包括傳統的資料結構(如連結串列,棧,佇列,圖等),也包括傳統的排序和查詢演算法。

JavaScript資料結構演算法 --- 棧

概念:表頭進行插入和刪除操作的線性表 核心思想:先進後出 作用:在程式語言的編譯器和記憶體中儲存變數、方法呼叫 操作方法:1)push() 進棧,即向棧裡新增元素                   2)pop() 出棧,即把元素從棧中刪除            

資料結構】5.1 順序表的查詢以及二分查詢的實現

類的結構如下: class StaticSearchTable { private: int *data; int data_number; bool search_seq(int loc,int key); void select_sort(); bool f

Javascript資料結構演算法--佇列(順序佇列優先佇列迴圈佇列)的實現用法

前言 佇列和棧非常類似,前面已經講過了棧的實現與用法,現在我們來說說佇列。 佇列介紹 佇列遵循FIFO(First In First Out,先進先出)原則的一組有序的項。 佇列是一種特殊的線性表,特殊之處在於它只允許在表的前端(front)進行刪除操作,而在表的後端(rear)進行插入操作,和棧一樣,佇列是

為什麼我要放棄javaScript資料結構演算法(第四章)—— 佇列

有兩種結構類似於陣列,但在新增和刪除元素時更加可控,它們就是棧和佇列。 第四章 佇列 佇列資料結構 佇列是遵循FIFO(First In First Out,先進先出,也稱為先來先服務)原則的一組有序的項。佇列在尾部新增新元素,並從頂部移除元素。最新新增的元素必須排在佇列的末尾。 現實中,很常見的例子就是排隊

javascript資料結構演算法筆記(四):迴圈佇列

javascript資料結構與演算法筆記(四):迴圈佇列 一:簡介 二:ES6版Queue類 一:簡介 迴圈佇列是指佇列頭元素的移除會追加到佇列的尾部。我們此次拿一個例子來實現迴圈佇列,例子名就是模擬民間遊戲擊鼓傳花即

javascript資料結構演算法筆記(三):優先佇列

javascript資料結構與演算法筆記(三):優先佇列 一:簡介 二:ES6版PriorityQueue類 一:簡介 優先佇列是元素的新增和移除是基於優先順序的。一個現實的例子就是機場登機的順序。頭等艙和商務艙乘客的

javascript資料結構演算法筆記(二):普通佇列

javascript資料結構與演算法筆記(二):普通佇列 一:簡介 二:ES6版Queue類 一:簡介 佇列是遵循FIFO( First In First Out, 先進先出,也稱為先來先服務)原則的一組有序的項。 佇

重讀《學習JavaScript資料結構演算法-第三版》- 第5章 佇列

定場詩 馬瘦毛長蹄子肥,兒子偷爹不算賊,瞎大爺娶個瞎大奶奶,老兩口過了多半輩,誰也沒看見誰! 前言 本章為重讀《學習JavaSc

JavaScript 資料結構演算法之美 - 線性表(陣列佇列連結串列)

前言 基礎知識就像是一座大樓的地基,它決定了我們的技術高度。 我們應該多掌握一些可移值的技術或者再過十幾年應該都不會過時的技術,資料結構與演算法就是其中之一。 棧、佇列、連結串列、堆 是資料結構與演算法中的基礎知識,是程式設計師的地基。 筆者寫的 JavaScript 資料結構與演算法之美 系列用

資料結構演算法分析c語言描述(Mark Allen)--佇列ADT連結串列實現

佇列ADT連結串列實現 使用連結串列儲存 操作集合 入隊 出隊 初始化 返回隊前元素 列印 #include <stdio.h> #includ

6.1-資料結構&演算法-堆疊佇列

----------------- 第七課  堆疊與佇列 一、資料結構的基本概念 1.邏輯結構 1)集合結構(集):結構中的元素除了同屬一個集之外,沒有任何聯絡。 2)線性結構(表):結構中的元素具有一對一的前後關係。

演算法資料結構番外(1):優先佇列

這是演算法與資料結構番外系列的第一篇,這個系列未來的主要內容是補充一些與演算法與資料結構相關的知識,這些知識比較零碎,同時也與[正傳](https://albertcode.info/?tag=algorithm)關係密切,往往需要閱讀了正傳的相關內容以後,才能較好的理解這部分內容。如果對番外系列不感興趣的話

為什麼我要放棄javaScript資料結構演算法(第一章)—— JavaScript簡介

資料結構與演算法一直是我算比較薄弱的地方,希望通過閱讀《javaScript資料結構與演算法》可以有所改變,我相信接下來的記錄不單單對於我自己有幫助,也可以幫助到一些這方面的小白,接下來讓我們一起學習。 第一章 JavaScript簡介 眾所周知,JavaScript是一門非常強大的程式語言,不僅可以用於

為什麼我要放棄javaScript資料結構演算法(第三章)—— 棧

有兩種結構類似於陣列,但在新增和刪除元素時更加可控,它們就是棧和佇列。 第三章 棧 棧資料結構 棧是一種遵循後進先出(LIFO)原則的有序集合。新新增的或待刪除的元素都儲存在棧的同一端,稱為棧頂,另一端就叫做棧底。在棧裡, 新元素都靠近棧頂,舊元素都接近棧底。 棧也被用在程式語言的編譯器和記憶體中儲存

為什麼我要放棄javaScript資料結構演算法(第五章)—— 連結串列

這一章你將會學會如何實現和使用連結串列這種動態的資料結構,這意味著我們可以從中任意新增或移除項,它會按需進行擴張。 本章內容 連結串列資料結構 向連結串列新增元素 從連結串列移除元素 使用 LinkedList 類 雙向連結串列 迴圈連結串列 第五章 連結串列 連結串列資

學習JavaScript資料結構演算法(第2版).epub

  【下載地址】 本書首先介紹了JavaScript 語言的基礎知識以及ES6 和ES7 中引入的新功能,接下來討論了陣列、棧、佇列、連結串列、集合、字典、散列表、樹、圖等資料結構,之後探討了各種排序和搜尋演算法,包括氣泡排序、選擇排序、插入排序、歸併排序、快速排序、堆排序、

為什麼我要放棄javaScript資料結構演算法(第十章)—— 排序和搜尋演算法

本章將會學習最常見的排序和搜尋演算法,如氣泡排序、選擇排序、插入排序、歸併排序、快速排序和堆排序,以及順序排序和二叉搜尋演算法。 第十章 排序和搜尋演算法 排序演算法 我們會從一個最慢的開始,接著是一些效能好一些的方法 先建立一個數組(列表)來表示待排序和搜尋的資料結構。 function Arra

為什麼我要放棄javaScript資料結構演算法(第十一章)—— 演算法模式

本章將會學習遞迴、動態規劃和貪心演算法。 第十一章 演算法模式 遞迴 遞迴是一種解決問題的方法,它解決問題的各個小部分,直到解決最初的大問題。遞迴通常涉及函式呼叫自身。 遞迴函式是像下面能夠直接呼叫自身的方式或函式 function recursiveFunction(someParam){

資料結構演算法精講版(陣列佇列連結串列遞迴排序二叉樹紅黑樹雜湊表)Java版

查詢和排序是最基礎也是最重要的兩類演算法,熟練地掌握這兩類演算法,並能對這些演算法的效能進行分析很重要,這兩類演算法中主要包括二分查詢、快速排序、歸併排序等等。我們先來了解查詢演算法! 順序查詢: 順序查詢又稱線性查詢。它的過程為:從查詢表的最後一個元素開始逐個與給定關鍵字比較,若某個記錄的關鍵字和給定值比較