1、冒泡排序
冒泡排序是一种最基础的排序算法,时间复杂度为O(n²),空间复杂度为O(1),可以把较小数字从后往前冒泡,也可把较小数字从前往后冒泡,取决于遍历开始值。具体代码如下:
function buddingSort(arr) {
for (let i = 0; i < arr.length; i++) {
for (let j = i + 1; j < arr.length; j++) {
if (arr[i] > arr[j]) {
[arr[i], arr[j]] = [arr[j], arr[i]]
}
}
}
return arr
}
使用解构赋值可以省掉两行代码
2、选择排序
选择排序基本逻辑为每次选择剩余元素中最小的值将其放到数组最前端,反之亦然,其时间复杂度和空间复杂度同冒泡排序。具体代码如下:
function selectSort(arr) {
let minIndex
for (let i = 0; i < arr.length; i++) {
minIndex = i
for (let j = i; j < arr.length; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j
}
}
[arr[i], arr[minIndex]] = [arr[minIndex], arr[i]]
}
return arr
}
3、插入排序
插入排序即为按顺序遍历数组,将小于当前值的数直接插入到当前位置,其他数字全部向后移一位,亦可逆序处理,时间复杂度和空间复杂度同冒泡排序。具体代码如下:
function insertSort(arr) {
let tmp
for (let i = 1; i < arr.length; i++) {
let j = i - 1
if (arr[i] < arr[j]) {
tmp = arr[i]
arr[j + 1] = arr[j]
j -= 1
while (j >= 0 && arr[j] > tmp) {
arr[j + 1] = arr[j]
j -= 1
}
arr[j + 1] = tmp
}
}
return arr
}
4、shell排序
shell排序为不稳定排序,是在插入排序上做了进一步的优化,使其平均时间复杂度降低到O(nlog2n)并且空间复杂度保持O(1),shell排序增量一般取数组长度一半开始进行一次选择排序,之后每次减半,知道增量为1时进行最后一次排序并结束算法。具体代码如下:
function shellSort(arr) {
let incre = Math.ceil(arr.length / 2)
while (incre >= 1) {
for (let i = 0; i < arr.length; i++) {
if (arr[i + incre] && arr[i] > arr[i + incre]) {
[arr[i], arr[i + incre]] = [arr[i + incre], arr[i]]
}
}
incre = Math.ceil((incre - 1) / 2)
}
return arr
}
5、快速排序
快速排序为选择一个基数,比基数小的全部放到前方,比基数大的放到基数后方,通过递归方式达到时间复杂度的优化,同时提高了更多的空间复杂度,时间复杂度为O(nlog2n),空间复杂度为O(log2n)。具体代码如下:
function quickSort(arr) {
if (isSorted(arr)) {
return arr
}
let sign = arr[0]
for (let i = 1; i < arr.length; i++) {
if (arr[i] > sign) {
const large = arr.splice(i, 1)[0]
arr.push(large)
}
if (arr[i] < sign) {
const small = arr.splice(i, 1)[0]
arr.unshift(small)
}
}
const signIndex = arr.indexOf(sign)
const largeArr = quickSort(arr.splice(signIndex + 1))
const smallArr = quickSort(arr.splice(0, signIndex))
return smallArr.concat([sign], largeArr)
}
function isSorted(arr) {
for (let i = 0; i < arr.length - 1; i++) {
if (arr[i] > arr[i + 1]) {
return false
}
}
return true
}