快速排序
顾名思义,他很快速,但也有其缺点,快速排序不能保证排序的稳定性,即当重复元素存在时,原数组中排在前面的元素,在排序后依然排在前面
快速排序是怎么做的
选取原数组中任意一个值,我这里取第一个元素,将比这个元素大的元素存放到bigger数组,比他小的存放到less数组,然后在分别对bigger和less数组做同样的操作,最后返回[...less + 选取元素 + ...bigger]
代码示例
// 快速排序
function quickSort(arr) {
if(arr.length < 2) return arr
const length = arr.length
const origin = arr[0]
const less = []
const bigger = []
for (let i = 1; i < length; i++) {
const item = arr[i]
item > origin ? bigger.push(item) : less.push(item)
}
const lessArr = quickSort(less)
const biggerArr = quickSort(bigger)
return lessArr.concat([origin]).concat(biggerArr)
}
计数排序
计数排序是用空间换时间的典型,比所有靠比较来排序的算法都快,且排序具有稳定性,但当需要排序的数组的最大值和最小值差距过大时,会非常损耗内存
计数排序是怎么做的
我们都知道数组的角标是升序的整数,那么创建一个新数组,原素组的元素作为角标,在那上之上元素的值,是该元素在原数组出现的次数,那么自然就会按照升序排列了
代码示例
function countingSort(arr) {
if (arr.length < 2) {
return arr
}
const countArr = []
// 计数
arr.forEach(item => {
// 注意,数组元素默认为 empty, 直接++ 会变成NaN
if(!countArr[item]) countArr[item] = 0
countArr[item]++
})
// 将计数的数组展开
let res = []
countArr.forEach((item, index) => {
if(item) {
let i = item
while(i > 0) {
res.push(index)
i--
}
}
})
return res
}
在这之上,我们可以做一些优化
首先是解决元素组最小值之前的位置全部为空,浪费空间的问题;
然后是使用累计数组,使排序具有稳定性
代码示例
// 计数排序
function countingSort(arr) {
let min = arr[0]
let max = arr[0]
// 获取最大最小值
arr.forEach(item => {
if(item > max) max = item
if(item < min) min = item
})
// 为了节省空间,小于最小值的空间没用,可以切掉
// 从 countArr 中取值要记得加 min
const countArr = new Array(max - min + 1).fill(0)
// 计数
arr.forEach(item => {
const index = item - min
countArr[index]++
})
// 使用累计数组来使排序稳定,
// 累计数组通过计数数组映射而来,它的元素值代表它在这个角标下,之前有多少个原数组的元素
// 我们知道了某个值前面有多少个比他小的值,就能知道他在最终数组中的角标
countArr.forEach((item, index) => {
if(index === 0) item = countArr[0]
else {
item += countArr[index - 1]
countArr[index] = item
}
})
// 获取结果时,需要注意如果原数组有相同元素,累计数组的值将是这些相同元素中最后一个的角标+1
// 而我们通过 countArr[index]-- 来循环添加,就会导致先来的元素进入到靠后的位置
// 所以要么靠前一个角标的值能查找第一个重复元素的位置(太麻烦),或者遍历时从后向前
const res = new Array(arr.length)
for(let i = arr.length - 1; i >= 0; i--) {
const item = arr[i]
res[--countArr[item - min]] = item
}
console.log('countArr', countArr);
return res
}