前言:我们常用的排序方式就是数组自带的sort方法,再进阶就是手写二分法排序,今天分享一篇模拟堆栈的方式实现快速排序,耗时比二分法排序提升一半的速度(具体提速度的的毫秒数我没做记录,我验证的是至少提升一半的速度;有兴趣的可以再验证下)
一、sort排序
let arr = [1,2,3,4,5.......] // 此处简单举例
let quickSort = function (arr) {
return arr.sort((a, b) => a - b) // 升序排序
}
quickSort(arr) // 调用
二、二分法排序
let arr = [1,2,3,4,5.......] // 此处简单举例
let quickSort = function (arr) {
// 如果数组为空则直接返回
if(!arr || arr.length < 1) return arr
// 获取到整个数组中间元素的下标
let middleIndex = Math.floor(arr.length / 2)
// 根据下表获取数组中间的元素并将此元素从原数组中剔除
let middleItem = arr.splice(middleIndex, 1)[0]
// 创建两个数组,leftArr用来接收比中间数小的元素;rightArr用来接收比中间数大的元素
let leftArr = []
let rightArr = []
// 循环数据根据中间数的大小将元素拆分为两个数组
for (let i = 0; i < arr.length; i++) {
if (arr[i] < middleItem) {
leftArr.push(arr[i])
} else {
rightArr.push(arr[i])
}
}
// 数据递归拼接返回
return [...quickSort(leftArr), middleItem, ...quickSort(rightArr)]
}
quickSort(arr) // 调用
三、模拟堆栈排序
let arr = [1,2,3,4,5.......] // 此处简单举例
// 定义快速排序函数,参数arr是需要排序的数组
let quickSort = function(arr) {
// 创建一个空栈,用于保存待处理的子数组范围
const stack = []
// 将第一个子数组范围入栈,初始范围是整个数组
stack.push({ left: 0, right: arr.length - 1 })
// 当栈不为空时,继续处理
while (stack.length > 0) {
// 弹出栈顶的子数组范围
const { left, right } = stack.pop()
// 如果子数组只有一个元素或者没有元素,则继续处理下一个子数组范围
if (right <= left) continue
// 计算中间元素的索引
const pivotIndex = Math.floor((left + right) / 2)
// 获取中间元素的值
const pivot = arr[pivotIndex]
// 初始化左指针和右指针,分别指向子数组的起始和结束位置
let i = left
let j = right
// 使用中间元素将数组分为两部分,直到i和j相遇或交错
while (i <= j) {
// 如果左边的元素小于中间元素,则左指针右移
while (Number(arr[i]) < Number(pivot)) i++
// 如果右边的元素大于中间元素,则右指针左移
while (Number(arr[j]) > Number(pivot)) j--
// 如果左指针小于或等于右指针,则交换两个元素并移动指针
if (i <= j) {
[arr[i], arr[j]] = [arr[j], arr[i]]
i++
j--
}
// 将左边的子数组范围入栈,以便下次处理
if (left < j) stack.push({ left, right: j })
// 将右边的子数组范围入栈,以便下次处理
if (i < right) stack.push({ left: i, right })
}
}
// 返回排序后的数组
return arr
}
quickSort(arr) // 调用