一、冒泡排序
// 冒泡排序
var bubbleSort = function (arr) {
const len = arr.length;
for (let i = 0; i < len; i++) {
let isSwap = false;
for (let j = 0; j < len - 1; j++) {
// 每一次遍历都要比较相邻元素的大小,如果满足条件就交换位置
if (arr[j] > arr[j + 1]) {
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
isSwap = true;
}
}
// 如果遍历完数组后没有发生交换,说明已经排序好了,跳出循环,中断剩余操作
if (!isSwap) {
break;
}
}
return arr;
}
console.log(bubbleSort([7, 3, 2, 21, 12, 1, 4, 9, 10]));
二、选择排序
// 选择排序
var selectionSort = function (arr) {
const len = arr.length;
// 外循环的 i 指向需要替换的位置,而 i 之前是已经排序的数组
for (let i = 0; i < len - 1; i++) {
let minIndex = i;
// 内循环是在未排序好的数组中找最小值的索引
for (let j = i + 1; j < len; j++) {
if (arr[minIndex] > arr[j]) {
minIndex = j;
}
}
// 找到最小值的索引后交换位置即可
[arr[i], arr[minIndex]] = [arr[minIndex], arr[i]];
}
return arr;
}
console.log(selectionSort([7, 3, 2, 21, 12, 1, 4, 9, 10]));
三、插入排序
// 插入排序
var insertionSort = function (arr) {
const len = arr.length;
for (let i = 1; i < len; i++) {
base = arr[i]; // 将未排序数组中的第一个元素作为基数
let j = i - 1; // j 指向已排序好的数组的最后一个元素
while (j >= 0 && arr[j] > base) {
arr[j + 1] = arr[j]; // 如果以上满足条件,元素 arr[j] 后移一位
j--; // 向前遍历
}
// 因为 j 在最后一次循环中减了一次,此时 j + 1 之后的元素都小于 base,所以 base 要插入的正确的位置是 j + 1
arr[j + 1] = base;
}
return arr;
}
console.log(insertionSort([7, 3, 2, 21, 12, 1, 4, 9, 10]));
四、快速排序
// 快速排序 O(n log n)
// 分治
var partition = function (arr, left, right) {
let i = left, j = right;
let base = arr[left]; // 每次将 arr[left] 作为基数
while (i < j) {
// 在右边数组找比基数小的数的索引
while (i < j && arr[j] >= base) {
j--;
}
while (i < j && arr[i] <= base) {
i++;
}
// 交换位置
[arr[i], arr[j]] = [arr[j], arr[i]];
}
// 此时 i 索引指向的就是基数应该处于的位置
[arr[i], arr[left]] = [arr[left], arr[i]];
console.log("arr:", arr);
return i;
}
// 递归
var quickSort = function (arr, left, right) {
// 递归终止条件
if (left >= right) {
return;
}
// 递归操作
// 找到基数所在的索引作为中间支点
let pivot = partition(arr, left, right);
// 左递归
quickSort(arr, left, pivot - 1);
// 右递归
quickSort(arr, pivot + 1, right);
}
let arr = [7, 3, 2, 21, 12, 1, 4, 9, 10, 31, 64, 108, 13, 5];
let len = arr.length - 1;
quickSort(arr, 0, len);
五、归并排序
// 归并排序
var mergeSort = function (arr) {
// 递归终止条件
if (arr.length <= 1) {
return arr;
}
// 递归操作
const mid = arr.length / 2;
// 拆分数组
const leftArr = mergeSort(arr.slice(0, mid));
const rightArr = mergeSort(arr.slice(mid));
return merge(leftArr, rightArr);
}
// 归并操作
var merge = function (leftArr, rightArr) {
let left = 0, right = 0;
let ans = [];
// 按需归并
while (left < leftArr.length && right < rightArr.length) {
if (leftArr[left] <= rightArr[right]) {
ans.push(leftArr[left]);
left++;
} else {
ans.push(rightArr[right]);
right++;
}
}
// 剩余元素直接追加
return ans.concat(leftArr.slice(left)).concat(rightArr.slice(right));
}
// ======== 测试 ========
const arr = [7, 3, 2, 21, 12, 1, 4, 9, 10, 108, 24, 35, 5, 8, 124];
console.log('排序后:', mergeSort(arr));
console.log('原数组是否改变:', arr); // 保持不变