この記事は(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、マージソート
再帰的に、アレイは、2つに分け、ソート二つの配列の後に、二つの配列をマージするたび
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、クイックソート
再帰的に、アレイ内の参照を選択するたびに、参照によるアレイは、二つに分割され、2つのソート配列、配列およびスプライシング二つの基準後にします
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')
[続きを読むデータ構造や記事のアルゴリズムシリーズ、見たデータ構造とアルゴリズムレビュー ]