功能
该方法对数组的元素进行排序并返回排序后的数组,同时改变原数组。
使用
不传参
sort方法在不传参的情况下总会以第一个字符的ASCII值来进行比较排序
const arr = [1, 2, 3, 4, 5, 6, 7, 11, 22, 33, 44]
const arr2 = ['a', 'd', 'c', 'e', 'b']
console.log(arr.sort()) // 1, 11, 2, 22, 3, 33, 4, 44, 5, 6, 7
console.log(arr2.sort()) // a, b, c, d, e
传参
接收一个函数,函数中接受两个参数a和b,a比较的第一个元素,b比较的第二个元素,可指定a - b或b - a对该数组进行升序或降序
const arr = [5, 2, 4, 1, 6, 3]
arr.sort((a, b) => b - a)
console.log(arr) // 6, 5, 4, 3, 2, 1
arr.sort((a, b) => a - b)
console.log(arr) // 1, 2, 3, 4, 5, 6
回调函数控制排序方式的实现原理
冒泡排序
sort 方法内部排序思想即冒泡排序思想,通过比较相邻的两个数,从而根据比较的大小进行位置的交换,冒泡排序的核心便是交换两个变量的地方
// 冒泡排序-从大到小
const arr = [2, 3, 4, 5, 6, 7, 8, 1]
// 外层循环控制趟数,每一趟找到一个最大值
for (let i = 0; i < arr.length; i++) {
// 内层循环控制比较的次数,并且判断两个数的大小,大的往前移,小的往后移
for (let j = 0; j < arr.length - 1 - i; j++) {
// 判断比较的第一个是否大于比较的第二个
if (arr[j] < arr[j + 1]) {
// 该判断体内进行变量的交换,也正是冒泡排序的核心
// 通过es6变量的解构赋值进行变量的交换,也可以通过临时变量进行交换
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]
}
}
}
console.log(arr) // 8, 7, 6, 5, 4, 3, 2, 1
性能优化
按照上面的代码,我们实现了对一组数字进行从大到小的排序 设问我们如果将一组已经从大到小排序好了的数组再通过上面的方式进行排序,循环次数是否还是一样,我们需要减少没有必要的循环
// 乱序数组-从大到小进行排序
let count = 0 // 声明一个变量记录循环次数
const arr = [2, 3, 4, 5, 6, 7, 8, 1]
for (let i = 0; i < arr.length; i++) {
count ++
for (let j = 0; j < arr.length - 1 - i; j++) {
count ++
if (arr[j] < arr[j + 1]) {
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]
}
}
}
// 记录了外层循环与内层循环的总和
console.log(count) // 36
// 降序数组-从大到小进行排序
let count = 0 // 声明一个变量记录循环次数
const arr = [8, 7, 6, 5, 4, 3, 2, 1]
for (let i = 0; i < arr.length; i++) {
count ++
for (let j = 0; j < arr.length - 1 - i; j++) {
count ++
if (arr[j] < arr[j + 1]) {
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]
}
}
}
// 记录了外层循环与内层循环的总和
console.log(count) // 36
可以发现不管是乱序的还是已经排序了的,循环次数都是为36次,如果一组比较多的数据通过这样的形式进行排序,性能必然会降低
// 优化
let count = 0
let isSort // 记录是否已经排序好了
const arr = [8, 7, 6, 5, 4, 3, 2, 1]
for (let i = 0; i < arr.length; i++) {
// 在每一次外层循环中,我们假设都已经排序好了
isSort = true
count ++
for (let j = 0; j < arr.length - 1 - i; j++) {
count ++
// 冒泡排序中的核心就是两个变量交换位置的地方
if (arr[j] < arr[j + 1]) {
// 如果这个判断体内的代码执行了,就证明两两比较的条件成立,并且进行变量的交换,证明没有排序好
isSort = false
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]
}
}
// 在每一趟外层循环后,判断是否已经排序好
if (isSort) {
break // 跳出循环
}
}
console.log(count) // 8
通过优化后的代码,可以发现,循环次数已经降低到8次了,因为外层每趟循环是必须的
封装方法-控制升序或降序
使用某一方法或尝试着封装某一方法都可以按照以下几点进行
该方法的功能参数的定义以及参数的类型是否有返回值
/*
*@param {Array} arr 需要排序的一组数据
*@param {Function} fun 控制升序或降序的函数
*@return {Array}
*/
const _sort = (arr, fun) => {
let isSort
for (let i = 0; i < arr.length; i++) {
isSort = true
for (let j = 0; j < arr.length - 1 - i; j++) {
// 在两两比较中通过调用fun该函数进行控制升序或降序
if (fun(arr[j], arr[j + 1]) > 0) {
isSort = false
;[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]
}
}
if (isSort) {
break
}
}
return arr
}
const arr = [2, 3, 1, 4, 2, 6]
console.log(_sort(arr, (a, b) => a - b)) // 1, 2, 2, 3, 4, 6
console.log(_sort(arr, (a, b) => b - a)) // 6, 4, 3, 2, 2, 1