溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

JavaScript如何實(shí)現(xiàn)歸并排序

發(fā)布時(shí)間:2021-01-06 11:37:42 來(lái)源:億速云 閱讀:162 作者:小新 欄目:web開(kāi)發(fā)

小編給大家分享一下JavaScript如何實(shí)現(xiàn)歸并排序,希望大家閱讀完這篇文章之后都有所收獲,下面讓我們一起去探討吧!

javascript欄目在本文中,我們學(xué)習(xí) Merge Sort 背后的邏輯,并用 JavaScript 實(shí)現(xiàn)。最后,在空間和時(shí)間復(fù)雜度方面將歸并排序與其他算法進(jìn)行比較。

歸并排序背后的邏輯

歸并排序使用分而治之的概念對(duì)給定的元素列表進(jìn)行排序。它將問(wèn)題分解為較小的子問(wèn)題,直到它們變得足夠簡(jiǎn)單以至可以直接解決為止。

以下是歸并排序的步驟:

  1. 將給定的列表分為兩半(如果列表中的元素?cái)?shù)為奇數(shù),則使其大致相等)。

  2. 以相同的方式繼續(xù)劃分子數(shù)組,直到只剩下單個(gè)元素?cái)?shù)組。

  3. 從單個(gè)元素?cái)?shù)組開(kāi)始,合并子數(shù)組,以便對(duì)每個(gè)合并的子數(shù)組進(jìn)行排序。

  4. 重復(fù)第 3 步單元,直到最后得到一個(gè)排好序的數(shù)組。

以數(shù)組 [4, 8, 7, 2, 11, 1, 3] 為例,讓我們看一下歸并排序是如何工作的:

JavaScript如何實(shí)現(xiàn)歸并排序

用 JavaScript 實(shí)現(xiàn)歸并排序

首先實(shí)現(xiàn)一個(gè)將兩個(gè)已排序子數(shù)組合并為一個(gè)已排序數(shù)組的函數(shù) merge() 。要注意著兩個(gè)子數(shù)組是已經(jīng)被排好序的,這一點(diǎn)非常重要, merge() 函數(shù)只用于其進(jìn)行合并。

可以通過(guò)遍歷這兩個(gè)子數(shù)組來(lái)實(shí)現(xiàn):

function merge(left, right) {
    let arr = []
    // 如果任何一個(gè)數(shù)組為空,就退出循環(huán)
    while (left.length && right.length) {
        // 從左右子數(shù)組的最小元素中選擇較小的元素
        if (left[0] < right[0]) {
            arr.push(left.shift())  
        } else {
            arr.push(right.shift()) 
        }
    }
    
    // 連接剩余的元素,防止沒(méi)有把兩個(gè)數(shù)組遍歷完整
    return [ ...arr, ...left, ...right ]
}

在這個(gè)函數(shù)中,通過(guò)把兩個(gè)排好序的子數(shù)組(left、right)合并來(lái)獲得一個(gè)排好序的大數(shù)組。首先,創(chuàng)建一個(gè)空數(shù)組。之后在 leftright 兩個(gè)子數(shù)組中最小元素中的較小的一個(gè),并將其添加到空數(shù)組。我們只需要檢查 leftright 子數(shù)組中的第一個(gè)元素,因?yàn)樗鼈兪且雅藕眯虻摹?/p>

在這個(gè)過(guò)程中,從子數(shù)組中刪除了被選擇的元素(通過(guò) shift()  函數(shù)實(shí)現(xiàn))。繼續(xù)這個(gè)過(guò)程,直到其中一個(gè)子數(shù)組變?yōu)榭铡W詈蟀逊强兆訑?shù)組的剩余元素(因?yàn)樗鼈円呀?jīng)被排序)插入主數(shù)組的最后面。

現(xiàn)在有了合并兩個(gè)已排序數(shù)組的代碼,接下來(lái)為實(shí)現(xiàn)歸并排序算法的最終代碼。這意味著要繼續(xù)分割數(shù)組,直到最終只包含一個(gè)元素的數(shù)組為止:

function mergeSort(array) {
  const half = array.length / 2
  
  if(array.length < 2){
    return array 
  }
  
  const left = array.splice(0, half)
  return merge(mergeSort(left),mergeSort(array))
}

在代碼中先確定中點(diǎn),并用 splice() 函數(shù)將數(shù)組分為兩個(gè)子數(shù)組。如果元素?cái)?shù)量為奇數(shù),則左側(cè)的元素?cái)?shù)量會(huì)少一個(gè)。不斷的劃分?jǐn)?shù)組,直到剩下單個(gè)元素的數(shù)組(array.length < 2)。然后用之前實(shí)現(xiàn)的 merge() 函數(shù)合并子數(shù)組。

代碼實(shí)現(xiàn)后用前面的用例測(cè)試一下:

array = [4, 8, 7, 2, 11, 1, 3];
console.log(mergeSort(array));

輸出符合預(yù)期:

1,2,3,4,7,8,11

歸并排序的效率

歸并排序的最差時(shí)間復(fù)雜度為 $O(n\\log n)$,與快速排序的最佳情時(shí)間復(fù)雜度相同。歸并排序是目前最快的排序算法之一。

與快速排序不同,歸并排序不是in-place排序算法,這意味著除了輸入數(shù)組之外,它還會(huì)占用額外的空間。這是因?yàn)槲覀兪褂昧溯o助數(shù)組來(lái)存儲(chǔ)子數(shù)組。歸并排序的空間復(fù)雜度為  $O(n)$。

歸并排序的另一個(gè)優(yōu)點(diǎn)是非常適合多線程,因?yàn)槊總€(gè)被劃分出的一半都可以單獨(dú)排序。另一種常見(jiàn)的減少歸并排序運(yùn)行時(shí)間的方法是在到達(dá)相對(duì)較小的子數(shù)組時(shí)(大約 7 個(gè)元素)使用插入排序。這是因?yàn)椴迦肱判蛟谔幚硇⌒突驇缀跖藕眯虻臄?shù)組時(shí)表現(xiàn)非常好。

看完了這篇文章,相信你對(duì)“JavaScript如何實(shí)現(xiàn)歸并排序”有了一定的了解,如果想了解更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI