JavaScript數據結構——隊列的實現與應用

来源:https://www.cnblogs.com/jaxu/archive/2019/07/30/11268862.html
-Advertisement-
Play Games

隊列與棧不同,它遵從先進先出(FIFO——First In First Out)原則,新添加的元素排在隊列的尾部,元素只能從隊列頭部移除。 我們在前一篇文章中描述瞭如何用JavaScript來實現棧這種數據結構,這裡我們對應地來實現隊列。 與棧的實現方式類似,唯一不同的是從隊列移除元素時取的是隊列頭 ...


  隊列與棧不同,它遵從先進先出(FIFO——First In First Out)原則,新添加的元素排在隊列的尾部,元素只能從隊列頭部移除。

  我們在前一篇文章中描述瞭如何用JavaScript來實現棧這種數據結構,這裡我們對應地來實現隊列。

function Queue() {
    let items = [];

    // 向隊列添加元素(一個或多個)
    this.enqueue = function (element) {
        if (element instanceof Array) items = items.concat(element);
        else items.push(element);
    };

    // 從隊列移除元素
    this.dequeue = function () {
        return items.shift();
    };

    // 返回隊列中的第一個元素
    this.front = function () {
        return items[0];
    };

    // 判斷隊列是否為空
    this.isEmpty = function () {
        return items.length === 0;
    };

    // 返回隊列的長度
    this.size = function () {
        return items.length;
    };

    // 清空隊列
    this.clear = function () {
        items = [];
    };

    // 列印隊列內的所有元素
    this.print = function () {
        console.log(items.toString());
    };
}

  與棧的實現方式類似,唯一不同的是從隊列移除元素時取的是隊列頭部的元素(最先添加的),而棧則是取的頂部元素(最後添加的)。下麵是一些測試用例及返回結果:

let queue = new Queue();
console.log(queue.isEmpty()); // true

queue.enqueue('John');
queue.enqueue(['Jack', 'Camila']);
queue.print(); // John,Jack,Camila
console.log(queue.size()); // 3
console.log(queue.isEmpty()); // false
console.log(queue.front()); // John

console.log(queue.dequeue()); // John
queue.print(); // Jack,Camila

queue.clear();
queue.print(); // 

  註意,我們允許批量向隊列中添加元素,為此我們需要判斷enqueue方法的參數類型,如果參數是數組,則用concat()函數連接兩個數組,如果參數不是數組,則直接用push()函數將元素添加到隊列中。

  與棧的實現方式一樣,這裡我們也同樣給出用ES6的WeakMap類來實現的隊列版本。

let Queue = (function () {
    const items = new WeakMap();

    class Queue {
        constructor() {
            items.set(this, []);
        }

        enqueue (element) {
            let q = items.get(this);
            if (element instanceof Array) items.set(this, q.concat(element));
            else q.push(element);
        };

        dequeue () {
            let q = items.get(this);
            return q.shift();
        };

        front () {
            return items.get(this)[0];
        };

        isEmpty () {
            return items.get(this).length === 0;
        };

        size () {
            return items.get(this).length;
        };

        clear () {
            items.set(this, []);
        };

        print () {
            console.log(items.get(this).toString());
        };
    }

    return Queue;
})();

  這兩個版本的執行結果是一樣的,它們的區別我們在前一篇文章中已經提及過了,這裡不再贅述。

優先隊列

  所謂優先隊列,顧名思義,就是說插入到隊列中的元素可以根據優先順序設置先後順序。優先順序越高位置越靠前,優先順序越低位置越靠後。假設優先順序用數字來表示,如果數字越小表示的優先順序越高,形成的隊列就稱之為最小優先隊列,反之則稱之為最大優先隊列。下麵是實現的代碼:

function PriorityQueue() {
    let items = [];

    // 向隊列添加元素(一個或多個)
    // 參數obj的數據格式:{element, priority}
    this.enqueue = function (obj) {
        if (obj instanceof Array) {
            for (let i = 0, ci; ci = obj[i]; i++) {
                this.enqueue(ci);
            }
        }
        else {
            let added = false;
            for (let i = 0, ci; ci = items[i]; i++) {
                // 最小優先順序,即將priority值小的元素插入到隊列的前面
                if (obj.priority < ci.priority) {
                    items.splice(i, 0, obj);
                    added = true;
                    break;
                }
            }

            // 如果元素沒有插入到隊列中,則預設加到隊列的尾部
            if (!added) items.push(obj);
        }
    };

    // 從隊列移除元素
    this.dequeue = function () {
        return items.shift();
    };

    // 返回隊列中的第一個元素
    this.front = function () {
        return items[0];
    };

    // 判斷隊列是否為空
    this.isEmpty = function () {
        return items.length === 0;
    };

    // 返回隊列的長度
    this.size = function () {
        return items.length;
    };

    // 清空隊列
    this.clear = function () {
        items = [];
    };

    // 列印隊列內的所有元素
    this.print = function () {
        items.forEach(function (item) {
            console.log(`${item.element} - ${item.priority}`);
        });
    };
}

  可以看到,唯一有區別的只有enqueue方法。我們規定所有添加到優先隊列的元素都必須滿足{element, priority}這種JSON格式,以保證隊列中的每一個元素都有一個priority屬性來表示優先順序。如果要添加的元素的優先順序和隊列中已有元素的優先順序相同,仍然遵循隊列的先進先出原則。如果隊列中所有元素的優先順序比要添加的元素的優先順序都高,則將元素添加到隊列的末尾。我們將print()方法也做了一些調整,以方便查看輸出結果。

let queue = new PriorityQueue();
console.log(queue.isEmpty()); // true

queue.enqueue({element: 'John', priority: 2});
queue.enqueue([{element: 'Jack', priority: 1}, {element: 'Camila', priority: 1}]);
queue.print(); // Jack,Camila,John

  由於John的優先順序比其它兩個低,所以它被排在了最後面。雖然Jack和Camila的優先順序相同,但是Jack是在Camila之前先插入到隊列中的,所以Jack排在了Camila之前,這也符合了我們的預期。

迴圈隊列

   我們用一個小游戲“擊鼓傳花”來說明迴圈隊列在實際中的應用。

function hotPotato(nameList, num) {
    let queue = new Queue();

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

    let eliminated = '';
    while(queue.size() > 1) {
        for (let i = 0; i < num; i ++) {
            queue.enqueue(queue.dequeue());
        }
        eliminated = queue.dequeue();
        console.log(`${eliminated} has been eliminated.`);
    }

    return queue.dequeue();
}

let names = ['John', 'Jack', 'Camila', 'Ingrid', "Carl"];
let winner = hotPotato(names, 7);
console.log(`The winner is: ${winner}`);

  在這個游戲中,我們傳入由五個名字組成的數組,用來表示參加游戲的五個人,數字7表示每一輪要傳遞的次數。在每一個過程中,我們從隊列頭部取出一個元素加到隊列的尾部,當次數用完的時候,將隊列頭部的元素取出來,作為這一輪中被淘汰的人。讓我們來看一下具體的執行過程,一開始隊列中的順序是John, Jack, Camila, Ingrid, Carl,然後傳遞7次:

  1. Jack, Camila, Ingrid, Carl, John

  2. Camila, Ingrid, Carl, John, Jack

  3. Ingrid, Carl, John, Jack, Camila

  4. Carl, John, Jack, Camila, Ingrid

  5. John, Jack, Camila, Ingrid, Carl

  6. Jack, Camila, Ingrid, Carl, John

  7. Camila, Ingrid, Carl, John, Jack

  之後從隊列中取出的是Camila。反覆執行上述過程,直到隊列中的元素只剩一個,這個就是最後的贏家!

  下麵是完整的執行結果:

Camila has been eliminated.
Jack has been eliminated.
Carl has been eliminated.
Ingrid has been eliminated.
The winner is: John

   下一章我們繼續來看看如何用JavaScript來實現鏈表。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 可以使用{display:block}將內聯元素變為塊級元素,同時使用{display:inline}將塊級元素變為內聯元素。 {display:inline-block}又是怎麼回事,根據張鑫旭老師《CSS的世界》中的解釋可以理解為,每個元素都有兩個盒子,外在的盒子和內在的盒子,外在的盒子負責元素 ...
  • 點擊圖片看原圖 點擊後:(再次點擊取消) ...
  • 子頁面a.php代碼如下: 父頁面p.php代碼如下: 父頁面JavaScript代碼如下: ...
  • 一、HTML代碼如下: 二、JavaScript代碼如下: ...
  • 在畫路徑圖之前,首先得在package.json引入2個依賴 廢話不多說,直接上代碼 通過以上代碼,最終可以生成如下圖所示,點擊開始,點就會跟著模擬路徑跑,流動方向請看代碼註釋。 ...
  • 最近這段時間公司特別忙,新的一年新的開始新一代的創業者都會選擇每年的春天開始創業,對於創業者來說現在企業製作一個新的網站要花多少錢?是比較關註的一個問題,建站行業的價格每年都會有所變化,目前上海網站建設公司製作一個常規的企業站普遍價格在八九千元,知名的比較大的網路公司價格會在萬元以上,當然建站也有價 ...
  • Allot Transfer $(document).ready(function() { $('input[type=radio][name=bedStatus]').change(function() { if (this.value == 'allot') { alert("Allot Tha... ...
  • Web前端三大框架_angular.js 6.0(一) 需要視頻教程,看頭像昵稱處 一、Angular 6.0 1.1樣式 html中引入樣式:內嵌式,外鏈式,行內式。 ng6中組件引入樣式的方式也有三種: 外鏈式 ng6中,已經將css預編譯語言配置出來了,因此我們可以直接使用他們 在組件註解類中 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...