在前端开发中,Array.prototype.sort
是一个高频使用的方法。它不仅能满足简单的排序需求,还能借助自定义比较函数解决复杂问题。本文将带你深入理解 sort
的用法,并通过一道经典的算法题 「最大数问题」(LeetCode 179) 展示 sort
的实际应用。
一、JS 中的 sort
方法详解
1. 基础用法
js
const arr = [3, 1, 4, 1, 5, 9]
arr.sort()
console.log(arr) // [1, 1, 3, 4, 5, 9] ???
很多人以为这里输出一定是按数值升序,但实际上 JS 默认是按字符串的字典序排序:
- 内部会先将元素转为字符串
- 然后逐字符比较 ASCII/Unicode 编码
所以 [3, 1, 4, 1, 5, 9]
默认排序结果是 [1, 1, 3, 4, 5, 9]
,但如果有两位数,就会出问题:
js
[10, 2, 30].sort() // [10, 2, 30](按字典序 "1", "2", "3"...)
2. 自定义比较函数
为了按数值大小排序,我们需要传入一个 比较函数:
js
arr.sort((a, b) => a - b) // 升序
arr.sort((a, b) => b - a) // 降序
- 如果返回值 < 0,表示
a
排在b
前面 - 如果返回值 > 0,表示
a
排在b
后面 - 如果返回值 = 0,顺序不变
例如:
js
[10, 2, 30].sort((a, b) => a - b) // [2, 10, 30]
3. 排序稳定性
在 ES2019 之后,V8 引擎对 sort
进行了优化,保证了 稳定排序 。
这意味着如果两个元素相等,排序后它们的相对位置不变,这在实际业务中很重要。
二、sort
的应用案例:最大数问题(LeetCode 179)
题目描述
给定一组非负整数,重新排列它们的顺序,使其组成的数最大。
示例
输入:[3, 30, 34, 5, 9]
输出:"9534330"
解题思路
- 普通的数值排序不能解决这个问题,比如
30
和3
的顺序很关键:"330"
<"303"
,所以3
应该排在30
前面。
- 我们需要自定义比较规则:
- 对于
a
和b
,比较a+b
和b+a
的大小(字符串拼接后比较)。 - 如果
a+b > b+a
,则a
应该排在前面。
- 对于
代码实现
ts
function largestNumber(nums: number[]): string {
nums.sort((a, b) => {
const ab = a.toString() + b.toString()
const ba = b.toString() + a.toString()
return ba.localeCompare(ab) // 保证大的排前面
})
const result = nums.join('')
return result[0] === '0' ? '0' : result
}
// 示例
console.log(largestNumber([3, 30, 34, 5, 9])) // "9534330"
复杂度分析
- 排序:
O(n log n)
- 拼接字符串:
O(n)
- 总体:
O(n log n)
三、总结
- JS 中
sort
默认按字符串字典序排序,要按数值大小排序必须传入比较函数。 sort
的比较函数遵循:负数 → 前面,正数 → 后面,零 → 保持位置。- 最大数问题 是
sort
的经典应用,通过自定义比较逻辑,可以解决复杂的排序场景。
👉 以后遇到类似问题,不妨先想一想:能不能把问题转化为 "定义一个合适的比较规则" ,然后交给 sort
去完成?