前端面试常考的10大排序算法 助你轻松应对面试
2023-10-18 00:26:04
前端面试必考:10 大排序算法详解
简介
排序算法是一种将数据按照特定顺序排列的算法。在前端开发中,掌握基本的排序算法思想至关重要,尤其是对于大型数据处理和优化用户体验。本文将深入探讨前端面试中常考的 10 大排序算法,帮助你提升算法技能,在求职中脱颖而出。
1. 插入排序
插入排序是一种简单的排序算法,通过将待排序元素逐个插入到已排序的子序列中,从而完成排序。插入排序的时间复杂度为 O(n^2),空间复杂度为 O(1),适合于小规模数据集的排序。
function insertionSort(arr) {
for (let i = 1; i < arr.length; i++) {
let current = arr[i];
let j = i - 1;
while (j >= 0 && current < arr[j]) {
arr[j + 1] = arr[j];
j--;
}
arr[j + 1] = current;
}
return arr;
}
2. 冒泡排序
冒泡排序是一种直观的排序算法,通过比较相邻元素,将较小的元素“冒泡”到数组前端。冒泡排序的时间复杂度为 O(n^2),空间复杂度为 O(1),适合于教学或小型数据集的排序。
function bubbleSort(arr) {
for (let i = 0; i < arr.length - 1; i++) {
for (let j = 0; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
}
}
}
return arr;
}
3. 选择排序
选择排序通过不断找出待排序数组中的最小元素,并将其交换到数组首部,从而完成排序。选择排序的时间复杂度为 O(n^2),空间复杂度为 O(1),适合于小规模数据集的排序。
function selectionSort(arr) {
for (let i = 0; i < arr.length - 1; i++) {
let minIndex = i;
for (let j = i + 1; j < arr.length; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j;
}
}
[arr[i], arr[minIndex]] = [arr[minIndex], arr[i]];
}
return arr;
}
4. 快速排序
快速排序是一种高效的排序算法,通过选择一个基准元素,将数组分为两个子数组,并将基准元素放在中间位置,然后递归地对子数组进行排序。快速排序的时间复杂度为 O(n log n),空间复杂度为 O(log n),适合于大规模数据集的排序。
function quickSort(arr, left, right) {
if (left < right) {
let pivotIndex = partition(arr, left, right);
quickSort(arr, left, pivotIndex - 1);
quickSort(arr, pivotIndex + 1, right);
}
return arr;
}
function partition(arr, left, right) {
let pivot = arr[right];
let i = left - 1;
for (let j = left; j < right; j++) {
if (arr[j] < pivot) {
i++;
[arr[i], arr[j]] = [arr[j], arr[i]];
}
}
[arr[i + 1], arr[right]] = [arr[right], arr[i + 1]];
return i + 1;
}
5. 归并排序
归并排序是一种稳定的排序算法,通过将数组分成两半,递归地对每一半进行排序,然后合并两个有序的子数组,从而完成排序。归并排序的时间复杂度为 O(n log n),空间复杂度为 O(n),适合于大规模数据集的排序。
function mergeSort(arr) {
if (arr.length <= 1) {
return arr;
}
let mid = Math.floor(arr.length / 2);
let left = mergeSort(arr.slice(0, mid));
let right = mergeSort(arr.slice(mid));
return merge(left, right);
}
function merge(left, right) {
let result = [];
let i = 0;
let j = 0;
while (i < left.length && j < right.length) {
if (left[i] < right[j]) {
result.push(left[i]);
i++;
} else {
result.push(right[j]);
j++;
}
}
while (i < left.length) {
result.push(left[i]);
i++;
}
while (j < right.length) {
result.push(right[j]);
j++;
}
return result;
}
6. 堆排序
堆排序是一种不稳定的排序算法,通过将数组构建成一个堆,并不断将堆顶元素与堆底元素交换,从而完成排序。堆排序的时间复杂度为 O(n log n),空间复杂度为 O(1),适合于大规模数据集的排序。
function heapSort(arr) {
buildMaxHeap(arr);
for (let i = arr.length - 1; i >= 1; i--) {
[arr[0], arr[i]] = [arr[i], arr[0]];
heapify(arr, 0, i);
}
return arr;
}
function buildMaxHeap(arr) {
for (let i = Math.floor(arr.length / 2) - 1; i >= 0; i--) {
heapify(arr, i, arr.length);
}
}
function heapify(arr, i, size) {
let left = 2 * i + 1;
let right = 2 * i + 2;
let largest = i;
if (left < size && arr[left] > arr[largest]) {
largest = left;
}
if (right < size && arr[right] > arr[largest]) {
largest = right;
}
if (largest != i) {
[arr[i], arr[largest]] = [arr[largest], arr[i]];
heapify(arr, largest, size);
}
}
7. 计数排序
计数排序是一种稳定的排序算法,适用于范围有限的非负整数数组。计数排序的时间复杂度为 O(n + k),其中 k 是数组中最大值的范围,空间复杂度为 O(k)。
function countingSort(arr, maxValue) {
let count = new Array(maxValue + 1).fill(0);
for (let i = 0; i < arr.length; i++) {
count[arr[i]]++;
}
let sortedIndex = 0;
for (let i = 0; i < count.length; i++) {
while (count[i] > 0) {
arr[sortedIndex] = i;
sortedIndex++;
count[i]--;
}
}
return arr;
}
8. 桶排序
桶排序是一种不稳定的排序算法,适用于数据分布均匀的数据集。桶排序的时间复杂度为 O(n + k),其中 k 是桶的个数,空间复杂度为 O(n + k)。
function bucketSort(arr, bucketSize) {
let maxValue = Math.max(...arr);
let bucketCount = Math.ceil(maxValue / bucketSize);
let buckets = new Array(bucketCount);
for (let i = 0; i < buckets.length; i++) {
buckets[i] = [];
}
for (let i = 0; i < arr.length; i++) {
let bucketIndex = Math.floor(arr[i] / bucketSize);
buckets[bucketIndex].push(arr[i]);
}
let sortedIndex = 0;
for (let i = 0; i < buckets.length; i++) {
insertionSort(buckets[i]);
for (let j = 0; j < buckets[i].length; j++) {
arr[sortedIndex] = buckets[i][j];
sorted