快速排序c++代码_5 行代码实现快速排序(简易版)

对于经典算法,你是否也遇到这样的情形:学时觉得很清楚,可过阵子就忘了?本系列文章(老姚的-手写算法并记住它-系列)就尝试解决这个问题。

研读那些排序算法,细品它们的名字,其实都很贴切。比如快速排序,一个快字就能体现出其价值,因而它是用得最多的。

因为它相对难一些,本系列将分两篇文章讲解它。

本篇是一种简单实现版本,与归并排序做对比,摸清快排的总体思路。下一篇才是常见于各教程中的原地排序算法。

快速排序这个名字是针对其性能来起的,但很难让人做到见名知意。

所以,我给它重新起了个名字:归分排序

与归并算法一样,归分算法也是分而治之算法,讲究分、归、并。前者的重头戏在于如何去合并,后者的重头戏在于如何去划分。

4aedc2ec597f3a7f326c2cb2b277f961.png

上图中,先把数组按最后一个元素4作为分界点,把数组一分为三。左子部分全是小于等于4的,右子部分全是大于4的,它们可以进一步递归排序,最后合并这三部分。

其中,并和归相对容易些,该算法的核心是:如何把数组按分界点一分为三?

这一点对于我们JSer来说,非常容易,使用filter就能做到:

let pivot = array[array.length - 1]

let left = array.filter((v, i) => v <= pivot && i != array.length -1)

let right = array.filter(v => v > pivot)

其中left部分要排除掉分界点元素,因此要求不能是最后一个。

分,这个核心问题解决了,接下来我们来看看并和归。

关于并,要拼接三个数组,在JS中都有相应的API(比如concat),这里我们简单实用展开运算符即可:

let result = [...left, pivot, ...right]

至于递归,虽然它不符合线性思维,但其实也没啥难的。

只要有递归步骤(递归公式),很容翻译成代码的。

我们再回忆一下归分算法的步骤:

  1. 数组分成三部分left、pivot、right,使left<=pivot,right>pivot

  2. 递归处理left

  3. 递归处理right

  4. 合并三者结果

轻松翻译成代码:

function quickSort(array) {

let pivot = array[array.length - 1]

let left = array.filter((v, i) => v <= pivot && i != array.length -1)

let right = array.filter(v => v > pivot)

return [...quickSort(left), pivot, ...quickSort(right)]

}

递归是自身调用自身,不能无限次的调用下去,因此需要有递归出口(初始条件)。

它的递归出口是,当数组元素个数为小于2时,就是已经是排好序的,不需要再递归调用了。

因此需要在前面加入代码:

if (array.length < 2) return array

查看完整代码:codepen(https://codepen.io/laoyao/pen/bGbLjOY?editors=0012)。

至此,我们实现了一个快速排序简单版,它与归并排序相对。

这里总结一下,此版本的快速排序需要额外空间,空间复杂度为O(nlogn),不是本地排序。相等元素是不会交换前后顺序,因而是稳定排序(这与我们选择最后一个元素为分界点有关)。时间复杂度为O(nlogn)。

快速排序,要做到能分分钟手写出来,是需要掌握其排序原理的。关键在于,如何按照分界点把数组一分为三。至于递归,只要能说清楚递归步骤和出口,就能很容易写出来,不需要死记硬背的。

希望有所帮助,本文完。

最后

关注同名公众号【小生方勤】,这里会第一时间发布优质文章,我们一同进步。(可进交流群)

4744fc0548292294758ae2aaf1f98dd8.png

》点击这里给小生留言

多一个再看,小生便多一份欢喜
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值