这篇文章将会介绍最常见的排序算法(使用 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