JavaScript >> Javascript 文檔 >  >> JavaScript

JavaScript 中的計算機科學:歸併排序

合併排序可以說是您在計算機科學中學習的第一個有用的排序算法。合併排序的複雜度為 O(n log n),使其成為可用的更有效的排序算法之一。此外,歸併排序是一種穩定的排序(就像插入排序一樣),因此等價項的相對順序在排序前後保持不變。這些優勢就是為什麼 Firefox 和 Safari 使用歸併排序來實現 Array.prototype.sort() .

歸併排序的算法基於這樣一種思想,即合併兩個已排序的列表比處理單個未排序的列表更容易。為此,合併排序首先創建 n 個單項列表,其中 n 是原始列表中要排序的項目總數。然後,算法繼續將這些項目列表組合回單個排序列表。

合併兩個已經排序的列表是一個非常簡單的算法。假設您有兩個列表,列表 A 和列表 B。您從每個列表的前面開始並比較這兩個值。將較小的值插入結果數組。所以假設較小的值來自列表A;該值被放入結果數組中。接下來,將列表 A 中的第二個值與列表 B 中的第一個值進行比較。再一次,將兩個值中較小的一個放入結果列表中。因此,如果較小的值現在來自列表 B,那麼下一步是將列表 A 中的第二項與列表 B 中的第二項進行比較。代碼如下:

function merge(left, right){
    var result  = [],
        il      = 0,
        ir      = 0;

    while (il < left.length &#038;&#038; ir < right.length){
        if (left[il] < right[ir]){
            result.push(left[il++]);
        } else {
            result.push(right[ir++]);
        }
    }

    return result.concat(left.slice(il)).concat(right.slice(ir));
}</code>

這個函數合併兩個數組,leftright . il 變量跟踪要比較 left 的索引 而 ir right 也一樣 .每次添加一個數組中的值時,其對應的索引變量就會遞增。一旦其中一個數組用完,剩餘的值就會使用 concat() 添加到結果數組的末尾 .

merge() 函數非常簡單,但現在您需要組合兩個排序列表。如前所述,這是通過將數組拆分為多個單項列表,然後系統地組合這些列表來完成的。使用遞歸算法很容易做到這一點:

function mergeSort(items){

    // Terminal case: 0 or 1 item arrays don't need sorting
    if (items.length < 2) {
        return items;
    }

    var middle = Math.floor(items.length / 2),
        left    = items.slice(0, middle),
        right   = items.slice(middle);

    return merge(mergeSort(left), mergeSort(right));
}</code>

首先要注意的是包含零個或一個項目的數組的終端情況。這些數組不需要排序,可以按原樣返回。對於具有兩個或多個值的數組,首先將數組分成兩半,創建 leftright 數組。然後將這些數組中的每一個傳回 mergeSort() 將結果傳遞到 merge() .所以算法是先對數組的左半邊排序,再對數組的右半邊排序,然後合併結果。通過這個遞歸,最終你會到達一個點,將兩個單值數組合併。

這種合併排序的實現返回一個與傳入的數組不同的數組(這不是“就地”排序)。如果您想創建就地排序,那麼您可以隨時清空原始數組並用排序後的項目重新填充它:

function mergeSort(items){

    if (items.length < 2) {
        return items;
    }

    var middle = Math.floor(items.length / 2),
        left    = items.slice(0, middle),
        right   = items.slice(middle),
        params = merge(mergeSort(left), mergeSort(right));
    
    // Add the arguments to replace everything between 0 and last item in the array
    params.unshift(0, items.length);
    items.splice.apply(items, params);
    return items;
}</code>

這個版本的mergeSort() 函數將排序結果存儲在名為 params 的變量中 .替換數組中的項目的最佳方法是使用 splice() 方法,它接受兩個或多個參數。第一個參數是要替換的第一個值的索引,第二個參數是要替換的值的數量。每個後續參數都是要插入該位置的值。由於無法將值數組傳遞到 splice() , 你需要使用 apply() 並傳入前兩個參數和排序數組。所以,``和items.length 使用 unshift() 添加到數組的前面 這樣 apply() 可與 splice() 一起使用 .然後,返回原始數組。

歸併排序可能是您將學習的最有用的排序算法,因為它具有良好的性能和易於實現的特點。與我介紹的其他排序算法一樣,最好還是從原生 Array.prototype.sort() 開始 在嘗試自己實現其他算法之前。在大多數情況下,本機方法會做正確的事情並提供最快的實現。但是請注意,並非所有實現都使用穩定的排序算法。如果使用穩定的排序算法對您很重要,那麼您需要自己實現一個。

您可以獲得兩個版本的 mergeSort() 來自我的 GitHub 項目,JavaScript 中的計算機科學。


Tutorial JavaScript 教程
  1. D3 構建塊 #3:SVG 形狀和屬性

  2. React 中使用 useState() 的 Component 語法和 Component() 之間的一個實際區別

  3. Angular 14 NgSwitch 指令教程和示例

  4. React 中的去抖動 – 如何延遲 JS 函數

  5. React 中帶有 Canvas 和 requestAnimationFrame() 的動畫

  6. 了解 next.js 路由

  7. 使用 React 和 GraphQL 代碼生成的全棧、類型安全應用程序

  1. 加速 Tesla.com - 第 1 部分:圖像和 JS 縮小

  2. 你一直想要但不知道的 React CLI

  3. 無法從生成的列表中抓取元素

  4. CoffeeScript 中的 Pub Sub 實現

  5. 如何創建一個 React 表組件

  6. 禁用所有 jquery datepicker 輸入的自動完成

  7. 了解如何在 Javascript 和 React 中使用 localStorage

  1. [更新] 在 Tailwindcss 中使用 Svelte - 一種更好的方法

  2. 異步 JavaScript 如何在幕後工作?

  3. 診斷性能問題

  4. 我如何用 100 行代碼修復 UpWork.com