JavaScript實(shí)現(xiàn)合并(歸并)排序算法示例解析
JavaScript實(shí)現(xiàn)歸并排序算法詳解
說明
歸并排序(Merge Sort)算法,也叫合并排序,是創(chuàng)建在歸并操作上的一種有效的排序算法。算法是采用分治法(Divide and Conquer)的一個(gè)非常典型的應(yīng)用,且各層分治遞歸可以同時(shí)進(jìn)行。歸并排序思路簡(jiǎn)單,速度僅次于快速排序,為穩(wěn)定排序算法,一般用于對(duì)總體無序,但是各子項(xiàng)相對(duì)有序的數(shù)列。
歸并排序和選擇排序一樣,歸并排序的性能不受輸入數(shù)據(jù)的影響,但表現(xiàn)比選擇排序好的多,因?yàn)槭冀K都是O(n log n)的時(shí)間復(fù)雜度。代價(jià)是需要額外的內(nèi)存空間。
歸并排序是用分治思想,分治模式在每一層遞歸上有三個(gè)步驟:
分解(Divide):將n個(gè)元素分成個(gè)含n/2個(gè)元素的子序列。
解決(Conquer):用合并排序法對(duì)兩個(gè)子序列遞歸的排序。
合并(Combine):合并兩個(gè)已排序的子序列已得到排序結(jié)果。
實(shí)現(xiàn)過程
- 將所有數(shù)組項(xiàng)無限細(xì)分,得到1個(gè)個(gè)獨(dú)立的單元,也就是不斷分解。
- 將相近的兩兩進(jìn)行比較,按照已排序數(shù)組合并,形成(n/2)個(gè)序列,每個(gè)序列包含2個(gè)數(shù)字。
- 將上述兩個(gè)序列遞歸合并,按照已排序數(shù)組合并,形成(n/4)個(gè)序列,每個(gè)序列包含4個(gè)數(shù)字。
- 重復(fù)步驟2,直到所有元素合并排序完畢。
示意圖

性能分析
平均時(shí)間復(fù)雜度:O(nlogn)
最佳時(shí)間復(fù)雜度:O(n)
最差時(shí)間復(fù)雜度:O(nlogn)
空間復(fù)雜度:O(n)
排序方式:In-place
穩(wěn)定性:穩(wěn)定
JS第1種寫法,標(biāo)準(zhǔn)雙指針移動(dòng)比較
/**
* 歸并排序 ,采用分而治之(divide - conquer)的步驟
* 1. 分解(Divide),把待排序元素的序列分解為兩個(gè)子序列,以中間2分, 每個(gè)子序列包括一半成員。
* 2. 解決(Conquer),對(duì)每個(gè)子序列分別調(diào)用歸并操作, 進(jìn)行遞歸或非遞歸循環(huán)操作,完成內(nèi)部排序。
* 3. 合并(Combine),合并兩個(gè)排好序的子序列,生成排序結(jié)果。 歸并排序的最壞時(shí)間復(fù)雜度和平均時(shí)間復(fù)雜度均為O(nlogn)
*/
(function () {
// 將兩個(gè)有序數(shù)組合并為一個(gè)新的有序數(shù)組
function merge (arr, left, mid, right) {
// 先建立一個(gè)長(zhǎng)度等于原數(shù)組的臨時(shí)數(shù)組
const temp = []
// 左側(cè)指針
let i = left
// 右側(cè)指針
let j = mid + 1
// 臨時(shí)數(shù)組指針
let k = 0
// 當(dāng)左指針小于中間,且右指針不大于最右側(cè)時(shí)
while (i <= mid && j <= right) {
// 如果左側(cè)小于右側(cè),將數(shù)移到臨時(shí)數(shù)組中左側(cè)
if (arr[i] <= arr[j]) {
temp[k++] = arr[i++]
// 否則移動(dòng)到臨時(shí)數(shù)組右側(cè)
} else {
temp[k++] = arr[j++]
}
}
// 如果左邊數(shù)組還有數(shù)據(jù),就把左側(cè)剩余都放入到原數(shù)組后面
while (i <= mid) {
temp[k++] = arr[i++]
}
// 如果右側(cè)數(shù)組還有數(shù)據(jù),把剩下的數(shù)據(jù)放入到原數(shù)組后面
while (j <= right) {
temp[k++] = arr[j++]
}
// 將排序后的元素全部移動(dòng)到原數(shù)組中
let x = 0
while (left <= right) {
arr[left++] = temp[x++]
}
console.log('arr:', arr)
}
function mergeSort (arr, left, right) {
// 得到中間值
const mid = Math.floor((left + right) / 2)
// 如果左側(cè)小于右側(cè)則執(zhí)行合并排序
if (left < right) {
// 遞歸合并左側(cè)
mergeSort(arr, left, mid)
// 遞歸合并右側(cè)
mergeSort(arr, mid + 1, right)
// 合并左右結(jié)果
merge(arr, left, mid, right)
}
return arr
}
// test
const arr = [7, 11, 9, 10, 12, 13, 8, -2, 0, 8]
console.time('sort')
console.log('origin:', arr)
console.log('\r\nsorted:', mergeSort(arr, 0, arr.length - 1))
console.timeEnd('sort')
})();JS第2種寫法,雙指針移動(dòng)結(jié)合數(shù)組特性
(function () {
function mergeSort (arr) {
const len = arr.length
if (len < 2) {
return arr
}
// 取得當(dāng)前數(shù)組的中間位置
const mid = Math.floor(len / 2)
const left = arr.slice(0, mid)
const right = arr.slice(mid)
console.log('mergeSort arr:', arr, left, right)
// 遞歸調(diào)用,不斷重復(fù)直到當(dāng)前數(shù)組拆分剩1項(xiàng)
return merge(mergeSort(left), mergeSort(right))
}
// 將兩個(gè)有序數(shù)組進(jìn)行合并為一個(gè)新的有序數(shù)組
function merge (left, right) {
// 建立一個(gè)空數(shù)組,用來存放排序結(jié)果
const result = []
// 左右數(shù)組的長(zhǎng)度都不為空時(shí),則將兩個(gè)數(shù)組的第一個(gè)進(jìn)行比較
// 如左側(cè)小于右,則移除左側(cè)的內(nèi)容到結(jié)果數(shù)據(jù),反之移動(dòng)右側(cè)成員
while (left.length && right.length) {
if (left[0] <= right[0]) {
result.push(left.shift())
} else {
result.push(right.shift())
}
}
// 最后把剩余的左或者右側(cè)成員全部添加到結(jié)果數(shù)組
while (left.length) {
result.push(left.shift())
}
while (right.length) {
result.push(right.shift())
}
// 這樣一趟下來后,兩個(gè)數(shù)組就合并為一個(gè)新的排序數(shù)組
return result
}
})()鏈接
歸并排序算法源碼:https://github.com/microwind/algorithms/tree/master/sorts/mergesort
其他排序算法源碼:https://github.com/microwind/algorithms
以上就是JavaScript實(shí)現(xiàn)合并(歸并)排序算法示例解析的詳細(xì)內(nèi)容,更多關(guān)于JavaScript合并(歸并)排序算法的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
每天一篇javascript學(xué)習(xí)小結(jié)(String對(duì)象)
這篇文章主要介紹了javascript中的String對(duì)象知識(shí)點(diǎn),對(duì)String對(duì)象的基本使用方法,以及各種方法進(jìn)行整理,感興趣的小伙伴們可以參考一下2015-11-11
關(guān)于uniapp中onReachBottomDistance屬性的使用
這篇文章主要介紹了關(guān)于uniapp中onReachBottomDistance屬性的使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09
headjs實(shí)現(xiàn)網(wǎng)站并行加載但順序執(zhí)行JS
本文主要介紹如何使用head.js實(shí)現(xiàn)網(wǎng)站并行加載但順序執(zhí)行JS,提高網(wǎng)站加載速度。需要的朋友可以看下2016-11-11
ztree獲取當(dāng)前選中節(jié)點(diǎn)子節(jié)點(diǎn)id集合的方法
這篇文章主要介紹了ztree獲取當(dāng)前選中節(jié)點(diǎn)子節(jié)點(diǎn)id集合的方法,實(shí)例分析了ztree的方法transformToArray使用技巧,需要的朋友可以參考下2015-02-02

