「这是我参与2022首次更文挑战的第15天,活动详情查看:2022首次更文挑战」
快速排序
介绍
快速排序 通过这个名字,我们就知道他是排序算法中最快的 排序算法。
在 上一篇 已经介绍了一种 快速排序 的方法。
现在 介绍 快速排序 的第二种方式。第二种方法 其实也很好理解,其中用到了数据结构中的 双指针算法 中的 对撞指针,可以先看下对应的 数据结构-双指针算法 这篇文章的讲解
-
快速排序方式二 的原理就是:将给定一组数据,首先产生一个对撞指针,left 和 right 下标 分别对应,数据的 最左侧 和 最右侧。
然后默认选取最左侧数据下标为 基准点 ,所对应的值(基准点的值)保存起来,记作 temp。
然后从剩余的数据中,从 right 下标 所对应的值开始进行比对,如果值大于该 基准点的值 ,则 right--,若小于则 从 left 下标重新开始。
判断 left 所对应的值 是否小于该基准点的值,若小于,则 left++,若不小于,则将 left 的下标 和 right 的下标 的值进行交换。
循环进行,直到判断
left >= right,结束循环,并将 temp 值与 两个指针相遇 下标所对应的值 交换。
步骤详解
-
上图是给定的数据
const arr = [15,5,25,20,30,10] -
初始化 begin = 0,end = arr.length-1
-
获取 基准点 及 基准点的值:
// 基准点 let left = begin // 基准点的值 const temp = arr[begin]可得上图的 基准点 为下图紫色部分:0
且 基准点的值 为:15
-
从右开始先与 基准点的值 比较
let right = end while (left < right && arr[right] >= temp) right--由上面代码可知第一次的 right 为 5,所对应的值为 10
-
再从左开始先与 基准点的值 比较
while (left < right && arr[left] <= temp) left++由上面代码可知第一次的 left 为 2,所对应的值为 25
-
进行交换
if (left !== right) { // 交换 左右指针 所停位置的数 exchangeFunc(arr, left, right) }如果 left 小于 right,则交换两个指针 所对应的值。
-
重复进行
由于
left < right,所以需要继续上述重复进行上述步骤后,直到left >= right才能结束第一次循环。 -
交换第一次结果
循环结束后,进行 temp 和 两指针相交 位置的值进行交换。得到的结果为
arr = [10,5,15,20,30,25] -
递归 左右数据
由上图可知,此时数据被分为 左数组 和 右数据。我们需要递归操作得到最终的结果。
quickSort(arr, begin, left - 1) quickSort(arr, left + 1, end)
比较
为什么要讲解 快速排序 的 方式二 呢,第一种方式确实 是很好理解,但是不是 快速排序 的真正速度。
所以这里创建一份 百万条 随机数据:
const arr = []
for (let i = 0; i < 10000000; i++) {
const num = Math.floor(Math.random() * 10000000)
arr.push(num)
}
然后对两种方式 分别进行耗时比较:
- 第一种
console.time('耗时')
quickSort1(array2)
console.timeEnd('耗时')
- 第二种
console.time('耗时')
const a = quickSort(arr, 0, arr.length - 1)
console.timeEnd('耗时')
耗时对比图
可以看到,耗时相比,几乎是 7 倍的差距,而且数据越多,差距越大。
完整代码
const quickSort = (arr, begin, end) => {
// 左指针和右指针相等时候,说明只有一个值
if (begin >= end) return
let left = begin
let right = end
const temp = arr[begin] // 基准点,这里取数组第一个数作为 基准点 的值
// 左右指针相遇的时候退出扫描循环
while (left < right) {
// 右指针从 右向左扫描
while (left < right && arr[right] >= temp) right--
// 左指针从 左向右扫描
while (left < right && arr[left] <= temp) left++
if (left !== right) {
// 交换 左右指针 所停位置的数
exchangeFunc(arr, left, right)
}
}
// 最后交换 基准数 与 两个指针 相遇位置 的 数
exchangeFunc(arr, begin, left)
// 递归处理左右数组
quickSort(arr, begin, left - 1)
quickSort(arr, left + 1, end)
return arr
}
/**
* 进行交换
* @param {array} arr
* @param {number} A
* @param {number} B
*/
const exchangeFunc = (arr, A, B) => {
const temp = arr[B]
arr[B] = arr[A]
arr[A] = temp
}
总结
快速排序 方式二 与 方式一 相比的优点:
-
不用创建新的数组,开辟新内存。
-
在百万条数据下,速度极快。