这篇文章将会介绍最常见的排序算法(使用 JavaScript 语言实现)
PS:这里我会尽量使用语言无关的语法去写,大家不要太在意语言,重要的是算法的实现思路
1、冒泡排序
将数组分为有序区(左边)和无序区(右边)
每次从无序区的最后一个元素开始,一直向前冒泡到无序区的第一个位置,使其变成有序
function swap(A, i, j) {
if (i === j) return
[A[i], A[j]] = [A[j], A[i]]
}
function bubbleSort(A) {
for (let i = 0, ii = A.length - 1; i < ii; i++) {
let done = true
for (let j = A.length - 1; j > i; j--) {
if (A[j] < A[j - 1]) {
swap(A, j, j - 1)
done = false
}
}
if (done) break
}
}
2、选择排序
将数组分为有序区(左边)和无序区(右边)
每次从无序区中选择一个合适的元素,并将其交换到无序区的第一个位置,使其变成有序
function swap(A, i, j) {
if (i === j) return
[A[i], A[j]] = [A[j], A[i]]
}
function selectionSort(A) {
for (let i = 0, ii = A.length; i < ii; i++) {
let minIdx = i
for (let j = i, jj = A.length; j < jj; j++) {
if (A[j] < A[minIdx]) minIdx = j
}
swap(A, i, minIdx)
}
}
3、插入排序
将数组分为有序区(左边)和无序区(右边)
每次将无序区中的第一个元素,一直向前交换到有序区中的合适位置,使其变成有序
function insertionSort(A) {
for (let i = 1, ii = A.length; i < ii; i++) {
let v = A[i]
let j = i - 1
while (j >= 0) {
if (A[j] > v) {
A[j + 1] = A[j]
j -= 1
} else break
}
A[j + 1] = v
}
}
4、归并排序
递归进行,每次将数组一分为二,然后对两个数组排序后,合并两个数组
function mergeSort(arr) {
if (arr.length <= 1) return arr
let mid = Math.floor(arr.length / 2)
let left = arr.slice(0, mid)
let right = arr.slice(mid)
return merge(mergeSort(left), mergeSort(right))
}
function merge(left, right) {
let rs = [], lp = 0, rp = 0
while (lp < left.length && rp < right.length)
(left[lp] < right[rp]) ? rs.push(left[lp++]) : rs.push(right[rp++])
while (lp < left.length)
rs.push(left[lp++])
while (rp < right.length)
rs.push(right[rp++])
return rs
}
优化:原地排序,这样可以减少新建数组
function mergeSortHelper(A, T, i, j) {
if (i === j) return
let m = Math.floor((i + j) / 2)
mergeSortHelper(A, T, i, m)
mergeSortHelper(A, T, m + 1, j)
// merge
for (let k = i; k <= j; k++) T[k] = A[k]
let l = i, r = m + 1
for (let curr = i; curr <= j; curr++) {
if (l > m) A[curr] = T[r++]
else if (r > j) A[curr] = T[l++]
else if (T[l] < T[r]) A[curr] = T[l++]
else A[curr] = T[r++]
}
}
function mergeSort(A) {
mergeSortHelper(A, [], 0, A.length - 1)
}
优化:临时数组后半部分反向插入,这样可以不用检测边界情况
function mergeSortHelper(A, T, i, j) {
if (i === j) return
let m = Math.floor((i + j) / 2)
mergeSortHelper(A, T, i, m)
mergeSortHelper(A, T, m + 1, j)
// merge
for (let k = i; k <= m; k++) T[k] = A[k]
for (let k = 1; k <= j - m; k++) T[j - k + 1] = A[k + m]
let l = i, r = j
for (let curr = i; curr <= j; curr++) {
if (T[l] < T[r]) A[curr] = T[l++]
else A[curr] = T[r--]
}
}
function mergeSort(A) {
mergeSortHelper(A, [], 0, A.length - 1)
}
5、快速排序
递归进行,每次在数组中选择一个基准,根据基准将数组一分为二,然后对两个数组排序后,拼接两个数组和基准
function quickSort(arr) {
if (arr.length <= 1) return arr
// find pivot
let pivotIndex = Math.floor(arr.length / 2)
let pivot = arr.splice(pivotIndex, 1)[0]
// partition
let left = arr.filter(item => item <= pivot)
let right = arr.filter(item => item > pivot)
// recursive
return [...quickSort(left), pivot, ...quickSort(right)]
}
优化:原地排序,这样可以减少新建数组
function swap(A, i, j) {
if (i === j) return
[A[i], A[j]] = [A[j], A[i]]
}
function quickSortHelper(A, i, j) {
if (j <= i) return
// find pivot
let pivotIndex = Math.floor((i + j) / 2)
let pivot = A[pivotIndex]
// put pivot at last
swap(A, pivotIndex, j)
// partition
let l = i - 1
let r = j
do {
while (A[++l] < pivot) {}
while (l < r && pivot < A[--r]) {}
swap(A, l, r)
} while (l < r);
// put pivot in place
swap(A, j, l)
// recursive
quickSortHelper(A, i, l - 1)
quickSortHelper(A, l + 1, j)
}
function quickSort(A) {
quickSortHelper(A, 0, A.length - 1)
}
优化:使用栈替代递归
function swap(A, i, j) {
if (i === j) return
[A[i], A[j]] = [A[j], A[i]]
}
function quickSortHelper(A, i, j) {
let stack = []
stack.push(i)
stack.push(j)
while (stack.length > 0) {
j = stack.pop()
i = stack.pop()
// find pivot
let pivotIndex = Math.floor((i + j) / 2)
let pivot = A[pivotIndex]
// put pivot at last
swap(A, pivotIndex, j)
// partition
let l = i - 1
let r = j
do {
while (A[++l] < pivot) {}
while (l < r && pivot < A[--r]) {}
swap(A, l, r)
} while (l < r);
// undo the last swap
swap(A, l, r)
// put pivot in place
swap(A, l, j)
// load up stack
if (l - 1 > i) {
stack.push(i)
stack.push(l - 1)
}
if (j > l + 1) {
stack.push(l + 1)
stack.push(j)
}
}
}
function quickSort(A) {
quickSortHelper(A, 0, A.length - 1)
}
6、测试程序
var origin = Array.from({ length: 100000 }, x => Math.floor(Math.random() * 100000))
var arr4bubble = JSON.parse(JSON.stringify(origin))
var arr4selection = JSON.parse(JSON.stringify(origin))
var arr4insertion = JSON.parse(JSON.stringify(origin))
var arr4merge = JSON.parse(JSON.stringify(origin))
var arr4quick = JSON.parse(JSON.stringify(origin))
console.time(‘q‘)
quickSort(arr4quick)
console.timeEnd(‘q‘)
console.time(‘m‘)
mergeSort(arr4merge)
console.timeEnd(‘m‘)
console.time(‘i‘)
insertionSort(arr4insertion)
console.timeEnd(‘i‘)
console.time(‘s‘)
selectionSort(arr4selection)
console.timeEnd(‘s‘)
console.time(‘b‘)
bubbleSort(arr4bubble)
console.timeEnd(‘b‘)
【 阅读更多数据结构与算法系列文章,请看 数据结构与算法复习 】
原文地址:https://www.cnblogs.com/wsmrzx/p/12545457.html
时间: 2024-11-08 05:17:38