目录
排序
1.sort排序
在 JavaScript 中,sort函数是对数组进行排序的常用函数。sort函数采用了一种基于比较的排序算法,具体来说,它通过比较数组中的元素,根据排序规则将它们排成相应的顺序。
在默认情况下,sort函数会将数组中的元素转化为字符串,然后根据其 Unicode 编码值进行升序排序。例如,[20, 3, 12].sort() 的结果为 [12, 20, 3],因为这三个数字转化为字符串后,它们的编码值分别是 "12"、"20" 和 "3",按照 Unicode 编码值的升序排列,就是 ["12", "20", "3"]。
为了实现自定义的排序规则,sort函数接受一个比较函数作为参数。比较函数接受两个参数 a 和 b,分别表示数组中的两个元素,需要返回一个数值来指示它们的相对位置。如果返回值大于 0,则表示 a 在 b 后面;如果返回值小于 0,则表示 a 在 b 前面;如果返回值等于 0,则表示 a 和 b 在排序后保持原来的相对位置。
根据传入的比较函数不同,sort函数会使用不同的排序算法。在 V8 引擎中,sort函数会根据输入数组的大小和类型,选择使用快速排序或归并排序。当输入数组大小小于某个特定值时,sort函数会使用插入排序。
需要注意的是,sort函数在排序过程中会修改原始数组,因此需要在必要的情况下先创建原数组的一个副本再进行排序。
实现代码:
const numbers = [1, 3, 2, 10, 5]
numbers.sort() // [1, 10, 2, 3, 5]
// 按照数值大小排序
numbers.sort((a, b) => a - b) // [1, 2, 3, 5, 10]
// 按照数值大小的反向排序
numbers.sort((a, b) => b - a) // [10, 5, 3, 2, 1]
2.冒泡排序
原理:
比较相邻的两个元素大小,如果前一个元素比后一个元素大,就交换这两个元素的位置,不断地重复这个过程,直到整个序列按照从小到大的顺序排列。
执行流程:
1.比较所有的相邻元素,如果第一个比第二个大,就交换他们
2.一轮下来,就可以保证最后一个元素是最大的
3.执行n-1轮,即可完成排序
实现代码:
const Fn = (arr) => {
for (let i = 0; i < arr.length - 1; i++) {
for (let j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
const temp = arr[j]
arr[j] = arr[j + 1]
arr[j + 1] = temp
}
}
}
return arr
}
Fn([5, 8, 9, 1, 3, 6, 99]) // Array(7) [1,3,5,6,8,9,99]
3.选择排序
原理:
从未排序的序列中选择最小(或最大)的元素,将其排在已排序序列的头部/末尾,不断重复这个过程,直到所有元素都排序完成。
执行流程:
1.找到数组中的最小值,放到数组的第一位
2.找到数组的第二小的值,放到数组的第二位
3.依次类推,执行n-1轮
实现代码:
const selectionSort = (arr) => {
for (let i = 0; i < arr.length; i++) {
let minIndex = i
for (let j = i; j < arr.length; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j
}
}
if (minIndex !== i) {
const temp = arr[i]
arr[i] = arr[minIndex]
arr[minIndex] = temp
}
}
return arr
}
selectionSort([6, 4, 2, 9, 1, 12, 3, 65, 963, 1024, 999]) //[1,2,3,4,6,9,65,963,999,1024]
4.插入排序
原理:
将未排序序列的元素插入已排序序列中正确的位置,使得已排序的序列仍然有序。
执行流程:
1.从第二个数开始往前比较,比它大的话就往后排
2.以此类推,进行到最后一个数
实现代码:
const insertionSort = (arr) => {
for (let i = 1; i < arr.length; i++) {
let temp = arr[i];
let j = i;
while (j > 0) {
if (temp < arr[j - 1]) {
arr[j] = arr[j - 1];
} else {
break;
}
j--;
}
arr[j] = temp;
}
return arr
}
insertionSort([4, 6, 9, 21, 3, 6, 99, 255, 1024, 1]) // Array(10) [1,3, 4, 6, 6, 9, 21, 99, 255, 1024]
5.归并排序
原理:
归并排序(Merge Sort)是一种分治算法,其核心思想是将一个待排序序列分成两个子序列,对每个子序列进行递归排序,然后将两个已排序的子序列合并成一个有序序列。
执行流程:
1.从数组的中间进行劈开,一分为二
2.然后递归的对子数组进行分的操作,直到分成一个个单独的数
3.把两个数合并成有序数组,再对有序数组进行合并,直到合并成一个完整的有序数组
实现代码:
Array.prototype.mergeSort = () => {
const rec = (arr) => {
if (arr.length === 1) return arr
const mid = Math.floor((arr.length) >> 1)
const left = arr.slice(0, mid)
const right = arr.slice(mid, arr.length)
const orderLeft = rec(left)
const orderRight = rec(right)
const res = []
while (orderLeft.left || orderRight.length) {
if (orderLeft.length && orderRight.length) {
res.push(orderLeft[0] < orderRight[0] ? orderLeft.shift() : orderRight.shift())
} else if (orderLeft.length) {
res.push(orderLeft.shift())
} else if (orderRight.length) {
res.push(orderRight.shift())
}
}
return res
}
const ans = rec(this)
ans.forEach((item, index) => {
this[index] = item
})
}
const arr = [6, 9, 2, 4, 3, 69, 99, 1024, 999]
arr.mergeSort(arr)
6.快速排序
原理:
快速排序(Quick Sort)也是一种分治算法,其核心思想是通过选取一个基准值,将待排序序列分成两个子序列,其中一个序列中的所有元素都小于基准值,另一个序列中的所有元素都大于等于基准值,然后对两个子序列分别递归进行快速排序。
执行流程:
1.分区:选择一个基准,比基准大的放到基准的后面,比基准小的放到基准的前面
2.递归:递归的对基准前后的子数组进行分区
实现代码:
Array.prototype.fastSort = function () {
const rec = (arr) => {
if (arr.length === 1) {
return arr;
}
const left = []
const right = []
const standard = arr[0]
for (let i = 1; i < arr.length; i++) {
if (arr[i] < standard) {
left.push(arr[i])
} else {
right.push(arr[i])
}
}
return [...rec(left), standard, ...rec(right)]
}
const res = rec(this)
res.forEach((item, index) => {
this[index] = item
})
}
const arr = [6, 2, 5, 8, 9, 9, 23, 69]
arr.fastSort(arr)
搜索
1.二分搜索
原理:
采用分治策略,将要查找的键值与数组的中间元素进行比较,然后根据结果选择继续在左半部分或右半部分进行查找,直到找到要查找的元素或者确定要查找的元素不在数组中为止。
执行流程:
1.从数组的中间元素开始,如果中间元素正好是目标值,则搜索结束。
2.如果目标值大于或者小于中间元素,则在大于或小于中间元素的那一半数组中搜索
注意:
使用二分搜索的前提是这个数组是排好序的,如果没有排好序的话,使用sort方法先将数组排好序
实现代码:
Array.prototype.binarySearch = function (target) {
let min = 0
let max = this.length - 1
while (min <= max) {
let middle = Math.floor((min + max) / 2)
let element = this[middle]
if (target > element) {
min = middle + 1
} else if (target < element) {
max = middle - 1
} else {
return middle
}
}
return -1
}
const arr = [1, 2, 3, 4, 5, 6].binarySearch(6)
2.顺序搜索
原理:
从数组的第一个元素开始,逐个遍历数组中所有的元素,直到找到要查找的元素或者确定要查找的元素不在数组中。
执行流程:
1.遍历数组。
2.找到跟目标值相等的元素,就返回它的下标
3.遍历结束后,如果没有搜索到目标值,就返回-1
实现代码:
Array.prototype.sequentialSearch = function (target) {
for (let i = 0; i < this.length; i++) {
if (this[i] === target) {
return i
}
}
return -1
}
const arr = [6, 9, 5, 2, 7, 99].sequentialSearch(99)