データ構造とアルゴリズムの見直し()ソートアルゴリズム(I)

この記事は(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')

[続きを読むデータ構造や記事のアルゴリズムシリーズ、見たデータ構造とアルゴリズムレビュー ]

おすすめ

転載: www.cnblogs.com/wsmrzx/p/12545457.html