This article will introduce the most common sorting algorithm (using the JavaScript language)
PS: Here I will try to use language independent syntax to write, we should not be too concerned about the language, it is important to realize the idea of the algorithm
1, bubble sort
The array is divided into ordered regions (left) and disordered region (on the right)
Every beginning from the last element of disorder, has been bubbling to the first position ahead of disorder so that it becomes ordered
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. Select Sort
The array is divided into ordered regions (left) and disordered region (on the right)
From each of disorder in an appropriate element, and to exchange their position to the first disordered region, so that it becomes an orderly
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, insertion sort
The array is divided into ordered regions (left) and disordered region (on the right)
Each time the first element of disorder in the area, has been ordered into position forward exchange area, so that it becomes ordered
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, merge sort
Recursively, each time the array is divided into two, and after two arrays sort, merge two arrays
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
}
Optimization: In-situ sequencing, thus reducing the new array
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)
}
Optimization: temporary array latter part of reverse insertion, which can not detect the boundary case
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, Quick Sort
Recursively, each time selecting a reference in the array, the array according to the reference will be divided into two, and after two sorted arrays, arrays and splicing two reference
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)]
}
Optimization: In-situ sequencing, thus reducing the new array
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)
}
Optimization: use recursion stack replacement
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, the test program
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')
[Read More Data Structures and Algorithms series of articles, look at the data structures and algorithms review ]