1. 辅助函数
createArray
: 生成测试排序的数组:
function createArray(num) {
let res = [];
for (let i = 0; i < num; i++) {
res.push(Math.floor(Math.random() * num));
}
return res;
}
checkArraySorted
: 测试数组是否已经排序(从小到大):
function checkArraySorted(arr) {
let res = true;
for (let i = 0, length = arr.length - 1; i < length; i++) {
if (arr[i] > arr[i + 1]) {
res = false;
break;
}
}
return res;
}
compareFn
: 用户可以自定义的比较函数
function compareFn(a, b) {
return a - b;
}
实际执行的代码
let arr = createArray(10000);
arr = someSort(arr);
console.log(checkArraySorted(arr));
2. 排序
2.1 冒泡排序
/**
* 冒泡排序
* 复杂度: O(n2)
* 稳定
*/
function bubbleSort(arr, compareFn) {
let length = arr.length;
for (let i = 0; i < length; i++) {
for (let j = 0; j < length - i - 1; j++) {
if (compareFn(arr[j], arr[j + 1]) > 0) {
let temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
return arr;
}
2.2 选择排序
/**
* 选择排序
* 复杂度: O(n2)
* 稳定
*/
function selectSort(arr) {
let length = arr.length;
for (let i = 0; i < length; i++) {
let minIndex = i;
for (let j = i + 1; j < length; j++) {
if (compareFn(arr[j], arr[minIndex]) < 0) {
minIndex = j;
}
}
if (minIndex > i) {
let temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
}
return arr;
}
2.3 插入排序
核心原理: 假设前 i - 1 个元素已经排序好了, 为第 i 个元素在前 i 个元素中找到正确的位置;
特性: 稳定; 对于 nearly sorted 数组, 时间复杂度降为 O(n)
/**
* 插入排序
* 时间复杂度: 最差为O(n2), 空间复杂度: O(1)
*/
function insertSort(arr) {
let length = arr.length;
for (let outer = 1; outer < length; outer++) {
let inner = outer;
while (inner > 0 && compareFn(arr[outer], arr[inner - 1]) < 0) {
arr[inner] = arr[inner - 1];
inner--;
}
arr[inner] = arr[outer];
}
return arr;
}
2.4 归并排序
核心原理: 用二分法将数组递归拆分为一系列单元素数组, 再自底向上进行归并
/**
* 归并排序
* 时间复杂度: O(nlogn) 空间复杂度: O(nlogn)
*/
function mergeSort(arr) {
if (arr.length > 1) {
let mid = arr.length >> 1;
let left = mergeSort(arr.slice(0, mid));
let right = mergeSort(arr.slice(mid));
arr = merge(left, right);
}
return arr;
function merge(left, right) {
let i = j = 0;
let res = [];
while (left[i] && right[j]) {
if (compareFn(left[i], right[j]) < 0) {
res.push(left[i]);
i++;
} else {
res.push(right[j]);
j ++;
}
}
return res.concat(left[i] ? left.slice(i) : right.slice(j));
}
}
2.5 快速排序
核心原理: 选定一个主元(pivot), 将数组拆分成较大组和较小组, 再对较大组和较小组递归进行相同操作. 相比于归并排序自下而上排序, 快速排序是自上而下排序
2.5.1 快排1
/**
* 快速排序
* 时间复杂度: O(nlogn)
* 22.066ms
*
*/
function quickSort(arr) {
if (arr.length < 2) {
return arr;
}
let base = arr[0];
let less = [];
let greater = [];
for (let i = 1, length = arr.length; i < length; i++) {
if (compareFn(arr[i], base) > 0) {
greater.push(arr[i]);
} else {
less.push(arr[i]);
}
}
return quickSort(less).concat(base).concat(quickSort(greater));
}
2.5.2 快排2
function quickSort2(arr) {
return quick(arr, 0, arr.length - 1);
function quick(arr, left, right) {
if (right > left) {
let index = partition(arr, left, right);
if (left < index - 1) {
quick(arr, left, index - 1);
}
quick(arr, index, right);
}
return arr;
}
function partition(arr, left, right) {
let pivot = arr[(left + right) >> 1];
while (left <= right) {
while (compareFn(arr[left], pivot) < 0) {
left++;
}
while (compareFn(arr[right], pivot) > 0) {
right--;
}
if (left <= right) {
let temp = arr[left]
arr[left] = arr[right]
arr[right] = temp
left++;
right--;
}
}
return left;
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。