返回
前端排序算法手册:用JavaScript实现十大经典算法
前端
2023-10-01 18:26:05
作为前端开发人员,排序算法可能是我们经常忽略的一个方面。然而,掌握这些算法可以极大地提高我们的编码技能,并帮助我们解决各种复杂的问题。
本文将深入探讨十大经典排序算法,并使用JavaScript提供它们的实际实现。这些算法包括:
- 冒泡排序
- 选择排序
- 插入排序
- 归并排序
- 快速排序
- 堆排序
- 桶排序
- 计数排序
- 基数排序
- 桶排序
我们将深入了解每种算法的工作原理、复杂度以及在不同情况下的适用性。同时,我们将通过实际代码示例来演示这些算法,以帮助您更好地理解它们的实现。
冒泡排序
冒泡排序是一种简单直观的排序算法,它通过反复比较相邻元素来排序数组。它将较大的元素“冒泡”到数组的末尾。
function bubbleSort(arr) {
let swapped;
do {
swapped = false;
for (let i = 0; i < arr.length - 1; i++) {
if (arr[i] > arr[i + 1]) {
let temp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = temp;
swapped = true;
}
}
} while (swapped);
return arr;
}
选择排序
选择排序是一种基于比较的算法,它通过在数组中找到最小元素并将其放置在适当的位置来进行排序。
function selectionSort(arr) {
for (let i = 0; i < arr.length; i++) {
let minIndex = i;
for (let j = i + 1; j < arr.length; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j;
}
}
let temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
return arr;
}
插入排序
插入排序是一种高效的算法,特别适用于已经部分排序或几乎有序的数组。它通过将一个元素插入到前面已经排序的子数组中来进行排序。
function insertionSort(arr) {
for (let i = 1; i < arr.length; i++) {
let currentElement = arr[i];
let j = i - 1;
while (j >= 0 && arr[j] > currentElement) {
arr[j + 1] = arr[j];
j--;
}
arr[j + 1] = currentElement;
}
return arr;
}
归并排序
归并排序是一种稳定的排序算法,它使用分治策略对数组进行排序。它将数组分成较小的子数组,对它们进行排序,然后将它们合并回一个排序后的数组。
function mergeSort(arr) {
if (arr.length <= 1) {
return arr;
}
let mid = Math.floor(arr.length / 2);
let leftHalf = mergeSort(arr.slice(0, mid));
let rightHalf = mergeSort(arr.slice(mid));
return merge(leftHalf, rightHalf);
}
function merge(left, right) {
let merged = [];
while (left.length && right.length) {
if (left[0] <= right[0]) {
merged.push(left.shift());
} else {
merged.push(right.shift());
}
}
return [...merged, ...left, ...right];
}
快速排序
快速排序是一种高效的排序算法,它使用分治策略对数组进行排序。它通过选择一个基准元素将数组分成较小的子数组,然后递归地对这些子数组进行排序。
function quickSort(arr) {
if (arr.length <= 1) {
return arr;
}
let pivot = arr[arr.length - 1];
let left = [];
let right = [];
for (let i = 0; i < arr.length - 1; i++) {
if (arr[i] <= pivot) {
left.push(arr[i]);
} else {
right.push(arr[i]);
}
}
return [...quickSort(left), pivot, ...quickSort(right)];
}
堆排序
堆排序是一种基于比较的算法,它使用堆数据结构对数组进行排序。它通过将数组构建成一个堆,然后逐步弹出堆的根元素并将其放置在数组的末尾来进行排序。
function heapSort(arr) {
// 建立最大堆
for (let i = Math.floor(arr.length / 2) - 1; i >= 0; i--) {
heapify(arr, arr.length, i);
}
// 排序
for (let i = arr.length - 1; i >= 0; i--) {
// 将根元素与最后一个元素交换
let temp = arr[0];
arr[0] = arr[i];
arr[i] = temp;
// 对剩余的数组重新建立堆
heapify(arr, i, 0);
}
return arr;
}
function heapify(arr, n, i) {
let largest = i;
let left = 2 * i + 1;
let right = 2 * i + 2;
if (left < n && arr[left] > arr[largest]) {
largest = left;
}
if (right < n && arr[right] > arr[largest]) {
largest = right;
}
if (largest !== i) {
let temp = arr[i];
arr[i] = arr[largest];
arr[largest] = temp;
heapify(arr, n, largest);
}
}
桶排序
桶排序是一种非基于比较的排序算法,它通过将数组元素分配到不同大小的桶中来进行排序。
function bucketSort(arr, n) {
let buckets = [];
for (let i = 0; i < n; i++) {
buckets[i] = [];
}
// 将元素分配到桶中
for (let i = 0; i < arr.length; i++) {
let index = Math.floor(n * arr[i]);
buckets[index].push(arr[i]);
}
// 对每个桶进行排序
for (let i = 0; i < n; i++) {
buckets[i] = insertionSort(buckets[i]);
}
// 将排序后的桶合并到一个数组中
let sortedArr = [];
for (let i = 0; i < n; i++) {
sortedArr = [...sortedArr, ...buckets[i]];
}
return sortedArr;
}
计数排序
计数排序是一种非基于比较的排序算法,它适用于只包含有限数量不同元素的数组。
function countingSort(arr, max) {
let counts = new Array(max + 1).fill(0);
for (let i = 0; i < arr.length; i++) {
counts[arr[i]]++;
}
// 累加计数
for (let i = 1; i < counts.length; i++) {
counts[i] += counts[i - 1];
}
// 输出排序后的数组
let sortedArr = new Array(arr.length);
let j = arr.length - 1;
for (let i = max; i >= 0; i--) {
while (counts[i] > 0) {
sortedArr[j] = i;
counts[i]--;
j--;
}