开启算法之门:JavaScript必会排序算法大PK
2023-04-17 20:13:06
踏入算法殿堂,解锁排序奥秘
在计算机科学的世界里,算法是程序员的必备工具,而排序算法更是其中不可或缺的重要组成部分。JavaScript作为一门强大的编程语言,提供了丰富的排序算法,每种算法都有其独特的优势和适用场景。
排序算法的类型
排序算法可以分为两大类:比较排序 和非比较排序 。
- 比较排序 :通过比较元素的大小来排序,包括冒泡排序、选择排序、插入排序等。
- 非比较排序 :不需要比较元素的大小,包括计数排序、桶排序、基数排序等。
常见的排序算法
以下是JavaScript中常见的排序算法:
1. 冒泡排序
冒泡排序是一种最简单的排序算法,它通过不断比较相邻元素,将较大的元素“泡”到数组末尾。算法简单易懂,但效率较低,只适用于小规模数据排序。
function bubbleSort(arr) {
let swapped;
do {
swapped = false;
for (let i = 1; i < arr.length; i++) {
if (arr[i - 1] > arr[i]) {
[arr[i - 1], arr[i]] = [arr[i], arr[i - 1]];
swapped = true;
}
}
} while (swapped);
return arr;
}
2. 选择排序
选择排序通过在未排序部分寻找最值元素,并将其与当前位置的元素交换,以此实现排序。算法效率比冒泡排序更高,但仍属于低效算法。
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;
}
}
[arr[i], arr[minIndex]] = [arr[minIndex], arr[i]];
}
return arr;
}
3. 快速排序
快速排序是一种分治算法,通过递归的方式将数组划分为更小的子数组,再对子数组进行排序,最后合并子数组得到最终排序结果。算法效率极高,是目前最常用的排序算法之一。
function quickSort(arr) {
if (arr.length <= 1) return arr;
const pivot = arr[Math.floor(arr.length / 2)];
const left = [];
const right = [];
for (let i = 0; i < arr.length; i++) {
if (arr[i] < pivot) {
left.push(arr[i]);
} else if (arr[i] > pivot) {
right.push(arr[i]);
}
}
return [...quickSort(left), pivot, ...quickSort(right)];
}
4. 插入排序
插入排序是一种直观且高效的排序算法,通过将元素插入到已排序的子数组中,依次完成排序。算法在处理已排序或局部排序的数据时表现出色。
function insertionSort(arr) {
for (let i = 1; i < arr.length; i++) {
const key = arr[i];
let j = i - 1;
while (j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j];
j--;
}
arr[j + 1] = key;
}
return arr;
}
5. 希尔排序
希尔排序是一种改进的插入排序算法,通过设置不同的间隔,将数组划分为更小的子数组,再对子数组进行插入排序,最后合并子数组得到最终排序结果。
function shellSort(arr) {
const gap = Math.floor(arr.length / 2);
while (gap > 0) {
for (let i = gap; i < arr.length; i++) {
const key = arr[i];
let j = i - gap;
while (j >= 0 && arr[j] > key) {
arr[j + gap] = arr[j];
j -= gap;
}
arr[j + gap] = key;
}
gap = Math.floor(gap / 2);
}
return arr;
}
6. 归并排序
归并排序也是一种分治算法,通过递归的方式将数组划分为更小的子数组,再对子数组进行排序,最后合并子数组得到最终排序结果。算法效率稳定,是目前最常用的排序算法之一。
function mergeSort(arr) {
if (arr.length <= 1) return arr;
const mid = Math.floor(arr.length / 2);
const left = arr.slice(0, mid);
const right = arr.slice(mid);
return merge(mergeSort(left), mergeSort(right));
}
function merge(left, right) {
const 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++;
}
}
return [...result, ...left.slice(i), ...right.slice(j)];
}
7. 计数排序
计数排序是一种特殊的排序算法,适用于元素范围有限且分布均匀的数据。算法通过统计元素的出现次数,并根据统计结果确定元素的最终位置,以此实现排序。
function countingSort(arr, max) {
const count = new Array(max + 1).fill(0);
for (const num of arr) {
count[num]++;
}
let i = 0;
for (let j = 0; j <= max; j++) {
while (count[j] > 0) {
arr[i] = j;
i++;
count[j]--;
}
}
return arr;
}
8. 桶排序
桶排序适用于均匀分布数据的排序算法。算法通过将数组划分为多个桶,并将元素分配到相应的桶中,再对每个桶中的元素进行排序,最后合并各桶的排序结果得到最终排序结果。
function bucketSort(arr, bucketSize) {
const buckets = [];
for (let i = 0; i < bucketSize; i++) {
buckets.push([]);
}
for (const num of arr) {
const bucketIndex = Math.floor(num / bucketSize);
buckets[bucketIndex].push(num);
}
for (const bucket of buckets) {
bucket.sort((a, b) => a - b);
}
return [].concat(...buckets);
}
9. 基数排序
基数排序适用于非负整数的排序算法。算法通过从最低位到最高位,逐位比较和交换元素,以此实现排序。
function radixSort(arr) {
let max = Math.max(...arr);
for (let exp = 1; max / exp > 0; exp *= 10) {
countingSortByExp(arr, exp);
}
return arr;
}
function countingSortByExp(arr, exp) {
const count = new Array(10).fill(0);
for (const num of arr) {
const digit = Math.floor(num / exp) % 10;
count[digit]++;
}
for (let i = 1; i < 10; i++) {
count[i] += count[i - 1];
}
const output = new Array(arr.length);
for (let i = arr.length - 1; i >= 0; i--) {
const digit = Math.floor(arr[i] / exp) % 10;
const index = count[digit] - 1;
output[index] = arr[i];
count[digit]--;
}
for (let i = 0; i < arr.length; i++) {
arr[i] = output[i];
}
}
选择适合的排序算法
在选择排序算法时,需要考虑以下因素:
- 数据规模 :大规模数据需要使用更高效的算法,