JavaScript 的排序功能主要通过 Array.prototype.sort()
方法实现,但其底层机制和实现细节因引擎而异。本文将深入探讨 JavaScript 的默认排序行为、主流引擎的优化算法(如 TimSort),以及常见排序算法在 JavaScript 中的实现与应用。
Array.prototype.sort()
JavaScript 的 sort()
方法默认将元素转换为字符串,并按照 Unicode 码点(UTF-16 编码)升序排列。这一行为可能导致数字排序的“错误”结果:
[10, 2, 1].sort(); // 输出 [1, 10, 2]
通过传递一个比较函数,可实现自定义排序规则:
[10, 2, 1].sort((a, b) => a - b); // 输出 [1, 2, 10]
比较函数返回值的含义:
a
应排在 b
前面。b
应排在 a
前面。自 ES2019 起,规范要求 sort()
必须为稳定排序(即相等元素保持原始顺序)。主流引擎(如 V8)通过 TimSort 算法实现这一特性。
TimSort 由 Tim Peters 设计,结合了归并排序和插入排序的优点,适合处理现实中的部分有序数据(如时间序列、日志文件)。Python 的 sorted()
和 Java 的 Arrays.sort()
也采用此算法。
O(n)
,平均和最坏情况 O(n log n)
。O(n)
(需额外空间合并块)。function quickSort(arr) {
if (arr.length <= 1) return arr;
const pivot = arr[Math.floor(arr.length / 2)];
const left = [], right = [], equal = [];
for (const num of arr) {
if (num < pivot) left.push(num);
else if (num > pivot) right.push(num);
else equal.push(num);
}
return [...quickSort(left), ...equal, ...quickSort(right)];
}
O(n log n)
,最坏 O(n²)
(可通过三数取中法优化)。function mergeSort(arr) {
if (arr.length <= 1) return arr;
const mid = Math.floor(arr.length / 2);
const left = mergeSort(arr.slice(0, mid));
const right = mergeSort(arr.slice(mid));
return merge(left, right);
}
function merge(left, right) {
let result = [];
while (left.length && right.length) {
result.push(left[0] <= right[0] ? left.shift() : right.shift());
}
return result.concat(left, right);
}
O(n log n)
。function insertionSort(arr) {
for (let i = 1; i < arr.length; i++) {
let j = i;
while (j > 0 && arr[j] < arr[j - 1]) {
[arr[j], arr[j - 1]] = [arr[j - 1], arr[j]];
j--;
}
}
return arr;
}
O(n)
,平均 O(n²)
。算法 | 平均时间复杂度 | 空间复杂度 | 稳定性 | 适用场景 |
---|---|---|---|---|
TimSort | O(n log n) | O(n) | 是 | 通用场景,尤其部分有序数据 |
快速排序 | O(n log n) | O(log n) | 否 | 大规模随机数据 |
归并排序 | O(n log n) | O(n) | 是 | 需要稳定排序或外部排序 |
插入排序 | O(n²) | O(1) | 是 | 小规模或基本有序数据 |
sort()
**:多数情况下,引擎优化(如 TimSort)已足够高效。JavaScript 的排序功能通过 Array.prototype.sort()
提供,其底层实现因引擎而异,但现代引擎普遍采用 TimSort 兼顾效率和稳定性。开发者可根据需求选择内置方法或手动实现特定算法,同时需注意数据特性(规模、有序性)和稳定性要求。理解这些算法的原理和性能特征,有助于在复杂场景中做出最优决策。