const isSortable = v => {
if (!Array.isArray(v) || v.length < 2) {
throw 'Not an array or length less than 1'
}
}
/**
* 冒泡
* 相邻比较,第一层表示趟数,第二层表示当前趟需要比较的次数
* @param {*} arr
*/
const bubleSort = arr => {
isSortable(arr)
const { length } = arr
for (let i = 0; i < length; i++) {
for (let j = 0; j < length - i - 1; j++) {
arr[j] > arr[j + 1] && (arr.splice(j, 1, ...arr.splice(j + 1, 1, arr[j])))
}
}
}
/**
* 选择排序
* 选索引,第n趟选出第n小的索引。本趟跑完了进行比较
* @param {*} arr
*/
const selectionSort = arr => {
isSortable(arr)
const { length } = arr
for (let i = 0; i < length; i++) {
let cur = i
for (let j = i + 1; j < length; j++) {
arr[cur] > arr[j] && (cur = j)
}
arr[i] > arr[cur] && arr.splice(i, 1, ...arr.splice(cur, 1, arr[i]))
}
}
/**
* 插入排序
* 选元素,第n趟选出区间内最小的元素,放到合适的位置, 总是保证一定区间内有序
* 最好case, 数组有序,O(n)
* 最坏情况, 数组倒序,O(n²)
* @param {*} arr
*/
const insertionSort = arr => {
isSortable(arr)
for (let i = 1; i < arr.length; i++) {
// 比前一个元素小的时候才需要比较
if (arr[i] < arr[i - 1]) {
let cur = i
let temp = arr[cur]
while (cur > 0 && temp < arr[cur - 1]) {
arr[cur] = arr[cur - 1] // 后一个元素向前移动,腾出位置
cur-- // 继续向前比较
}
arr[cur] = temp
}
}
}
/**
* 快排
* 最优: 每一次划分都将数组分为等长的两半 O(nlogn)
* 最差, 每次划分都将数组分为0,n-1, O(n²)
* @param {*} arr
*/
const quickSort = arr => {
if (arr.length <= 1) {
return arr
}
const left = []
const right = []
const base = arr.splice(Math.floor(arr.length / 2), 1)[0]
for (let i = 0; i < arr.length; i++) {
arr[i] < base ? left.push(arr[i]) : right.push(arr[i])
}
return quickSort(left).concat(base, quickSort(right))
}
/**
* 测试
*/
const testSort = (arr, fn) => {
console.log(arr);
fn(arr)
console.log(arr)
}
const testQuickSort = (arr) => console.log(quickSort(arr))
const getMockArr = (length = 6) => Array.from({ length }).map(v => Math.floor(Math.random() * 100))
testSort(getMockArr(6), bubleSort)
testSort(getMockArr(6), selectionSort)
testSort(getMockArr(6), insertionSort)
testQuickSort(getMockArr(6))