本文介绍关于JS 常见6种排序方法,需要的朋友可以参考一下:
1、冒泡排序
冒泡排序的思路:从头到尾依次进行两两比较,前者大于后者,交换位置,反之不交换。每一轮排序后都会下沉一个最大值。(升序)
时间复杂度:
O
(
N
2
)
O(N^2)
O(N2);空间复杂度:
O
(
1
)
O(1)
O(1)
const rl = require("readline").createInterface({ input: process.stdin })
var iter = rl[Symbol.asyncIterator]()
const readline = async () => (await iter.next()).value
void async function () {
let arr = ((await readline()).split(' ')).map(Number)
console.log(bubbbleSort(arr).join(' '))
}()
function bubbbleSort (arr) {
let len = arr.length
if (len > 0) {
for (let i = len - 1; i > 0; i--) {
for (let j = 0; j < len; j++) {
if (arr[j] > arr[j + 1]) {
let temp = arr[j]
arr[j] = arr[j + 1]
arr[j + 1] = temp
}
}
}
return arr
} else {
return []
}
}
用例测试:
23 45 1 45 78 90 36 21
1 21 23 36 45 45 78 90
2、选择排序
选择排序的实现思路:第一次遍历数组把最小数放在头部;再从剩余元素中遍历选出最小的元素,直到待排序数的个数为0。
时间复杂度:
O
(
N
2
)
O(N^2)
O(N2);空间复杂度:
O
(
1
)
O(1)
O(1)
const rl = require("readline").createInterface({ input: process.stdin })
var iter = rl[Symbol.asyncIterator]()
const readline = async () => (await iter.next()).value
void async function () {
let arr = ((await readline()).split(' ')).map(Number)
console.log(SelectionSort(arr).join(' '))
}()
function SelectionSort (arr) {
let len = arr.length
if (len > 0) {
for (let i = 0; i < len - 1; i++) {
let minIndex = i
for (let j = i + 1; j < len; j++) {
minIndex = arr[j] < arr[minIndex] ? j : minIndex
}
let temp = arr[i]
arr[i] = arr[minIndex]
arr[minIndex] = temp
}
return arr
} else {
return []
}
}
用例测试:
0 2 4 1 5
0 1 2 4 5
3、插入排序
插入排序实现思路:每一个无序数列中的元素分别和有序数列中的每一个进行对比和交换,直到遇到比他小的,则停止交换,插入该元素;
时间复杂度:
O
(
N
2
)
O(N^2)
O(N2);空间复杂度:
O
(
1
)
O(1)
O(1)
/*
插入排序实现思路:每一个无序数列中的元素分别和有序数列中的每一个进行对比和交换,直到遇到比他小的,则停止交换,插入该元素;
「时间复杂度:O(N^2);」
「空间复杂度:O(1)」
*/
const rl = require("readline").createInterface({ input: process.stdin })
var iter = rl[Symbol.asyncIterator]()
const readline = async () => (await iter.next()).value
void async function () {
let arr = ((await readline()).split(' ')).map(Number)
console.log(insertSort(arr).join(' '))
}()
function insertSort (arr) {
let len = arr.length
if (len > 0) {
for (let i = 1; i < len; i++) {
let insertValue = arr[i]
// 从右向左遍历起始下标为第0位,结束下标为第i-1位(即无序序列前一位)
for (let j = i - 1; j >= 0; j--) {
if (insertValue < arr[j]) {
let temp = arr[j]
arr[j] = insertValue
arr[j + 1] = temp
}
}
}
return arr
} else {
return []
}
}
用例测试:
9 18 4 27 3 21 15 18 34 5 14
3 4 5 9 14 15 18 18 21 27 34
4、归并排序
归并排序的思路:将长度为n的数组反复二分为两个小数组,直到只剩下单个元素数组;从最小数组开始,两两按大小顺序合并,直到并为原始数组大小。(归并排序实际上就是一个二叉树的后序遍历过程)
时间复杂度:
O
(
N
∗
l
o
g
N
)
O(N * logN)
O(N∗logN);空间复杂度:
O
(
N
)
O(N)
O(N);
/*
Math.floor() 方法返回小于等于x的最大整数。如果传递的参数是一个整数,该值不变。
array.shift() 方法用于把数组的第一个元素从其中删除,并返回第一个元素的值。
注意: 此方法改变数组的长度!提示: 移除数组末尾的元素可以使用 pop() 方法。
array.slice(start,end) 方法可从已有的数组中返回选定的元素。
该方法可提取字符串的某个部分,并以新的字符串返回被提取的部分。
注意: slice() 方法不会改变原始数组。
*/
const rl = require("readline").createInterface({ input: process.stdin })
var iter = rl[Symbol.asyncIterator]()
const readline = async () => (await iter.next()).value
void async function () {
let arr = ((await readline()).split(' ')).map(Number)
console.log(mergeSort(arr).join(' '))
}()
// 拆分
function mergeSort (arr) {
let len = arr.length
if (len > 1) {
let middle = Math.floor(len / 2)
let left = arr.slice(0, middle)
let right = arr.slice(middle, len)
// 递归拆分
let mergeSortLeft = mergeSort(left)
let mergeSortRight = mergeSort(right)
// 排序
return mergeArr(mergeSortLeft, mergeSortRight)
} else {
return arr
}
}
// 合并
function mergeArr (left, right) {
let res = []
// left、right数组内都存在元素
while (left.length > 0 && right.length > 0) {
if (left[0] <= right[0]) {
// 每次都删除left或者right的第一个元素,将其加入res中
res.push(left.shift())
} else {
res.push(right.shift())
}
}
// left、right其中一个已为空
while (left.length) {
res.push(left.shift())
}
while (right.length) {
res.push(right.shift())
}
return res
}
用例测试:
2 4 5 1 3
1 2 3 4 5
5、快速排序
快速排序实现思路:随机取出一个值进行划分,大于该值放右边,小于该值放左边。(快速排序其实就是二叉树中前序遍历的处理方式)
时间复杂度:
O
(
N
∗
l
o
g
N
)
O(N*logN)
O(N∗logN);空间复杂度:
O
(
l
o
g
N
)
O(logN)
O(logN)
/*
splice() 方法用于添加或删除数组中的元素。注意:这种方法会改变原始数组。
如果删除一个元素,则返回一个元素的数组。 如果未删除任何元素,则返回空数组。
*/
const rl = require("readline").createInterface({ input: process.stdin })
var iter = rl[Symbol.asyncIterator]()
const readline = async () => (await iter.next()).value
void async function () {
let arr = ((await readline()).split(' ')).map(Number)
console.log(quickSort(arr).join(' '))
}()
function quickSort (arr) {
let len = arr.length
if (len > 1) {
let middleIndex = Math.floor(len / 2)
let middle = arr.splice(middleIndex, 1)[0]
let left = []
let right = []
arr.forEach(item => {
if (item < middle) {
left.push(item)
} else {
right.push(item)
}
})
return quickSort(left).concat(middle, quickSort(right))
} else {
return arr
}
}
用例测试:
9 18 4 27 3 21 15 18 34 5 14
3 4 5 9 14 15 18 18 21 27 34
6、堆排序
堆排序思路:
1.让数组变成大根堆
2.把最后一个位置和堆顶做交换
3.则最大值在最后,则剩下部分做heapify,则重新调整为大根堆,则堆顶位置和该部分最后位置做交换
4.重复进行,直到减完,则这样最后就调整完毕,整个数组排完序(为一个升序)
时间复杂度:
O
(
N
∗
l
o
g
N
)
O(N * logN)
O(N∗logN);空间复杂度:
O
(
1
)
O(1)
O(1);
/*
n节点的左子树为2*n+1,右子树为2*n+2,那么最后一个非叶子节点的值应该为Math.floor((arr.length-1-1)/2)
*/
const rl = require("readline").createInterface({ input: process.stdin })
var iter = rl[Symbol.asyncIterator]()
const readline = async () => (await iter.next()).value
void async function () {
let arr = ((await readline()).split(' ')).map(Number)
console.log(heapSort(arr).join(' '))
}()
// 将一个无序数组(二叉树),调整成一个大顶堆(升序)
function adjustHeap (arr, i, len) {
let temp = arr[i]
// j=i*2+1为左子节点
for (let j = i * 2 + 1; j < len; j = j * 2 + 1) {
// ①左子节点值小于右子节点值——j指向右子节点
if (j + 1 < len && arr[j] < arr[j + 1]) {
j++
}
// ②子节点值大于父节点值——把较大值赋值给当前节点
if (arr[j] > temp) {
arr[i] = arr[j]
i = j
} else {
break
}
// for循环结束以i为父节点的树的最大值放已在最顶部
//将temp值放到调整后的位置
arr[i] = temp
}
}
// 堆排序
function heapSort (arr) {
let len = arr.length
// 大顶堆
for (let i = Math.floor(len / 2) - 1; i >= 0; i--) {
adjustHeap(arr, i, len)
}
// 重复执行堆顶元素与末尾元素交换,将最大元素“沉”到数组末端,直到整个序列有序
for (let j = len - 1; j > 0; j--) {
let temp = arr[j]
arr[j] = arr[0]
arr[0] = temp
adjustHeap(arr, 0, j)
}
return arr
}
用例测试:
7 3 6 9 24 0 1 45 8
0 1 3 6 7 8 9 24 45
总结
到此关于JavaScript中6种常见数组排序算法的介绍就结束了,更多关于JS算法刷题常用知识点后续还会更新,在阅读过程中如若有误,劳请指正;如若有妙解、疑惑也欢迎大家和我交流,感谢!