0
点赞
收藏
分享

微信扫一扫

算法-快速排序

搬砖的小木匠 2021-09-24 阅读 77

快速排序的平均时间复杂度是 O(nlogn),但最坏情况下会变成 O(n2)。核心思想是分治法,也就是说选定一个标准,将数组的值划分为大于标准,和小于等于标准两组,直到不能继续划分为止。所以这里的关键也在于这个标准值要怎么取。通常的取法是取数组第一位,或者随机一个数在与第一位交换。

快速排序的优势在于,数组处于乱序状态下会有一个较好的表现。

思路

实现的思路主要在于怎么划分,这里就以数组第一位为标准值。划分操作可分为两种,

  • 单边循环
    这个比较符合我们一开始的思路,遍历数组,然后通过对比,我们最终想要的效果是小的在左,大的在右,基值(标准值)在中间。
    具体步骤是这样,
  1. 标记当前 <= 基值的边界,然后从基值(基值这里取数组第一位,即下标为 0 的那位)后一位开始遍历。
  2. 当遍历发现 <= 基值时,这个标记就 +1 表示边界扩大了,并且在当前遍历的下标与标记不相同时,交换元素。
  3. 当遍历发现 > 基值时,就继续遍历。
  4. 遍历结束后,<= 基值的都在前面,> 基值的都在后面,此时再交换一下基值与标记的元素,就是我们想要的小的在左,大的在右,基值在他们中间。
  5. 这样完成了一趟分治,接着利用递归,分别对基值左边和基值右边的数组重复上面四步,直到数组没办法再划分为止。
  • 双边循环
    意思是分别从数组的两头开始与基值(标准值)比较,这样看来会比单边循环效率高些。
    具体步骤是这样,
  1. 确定好数组的左右两头,基值依然选择数组的第一位。
  2. 在左右两头标记不想碰(left < right 或者 left != right)的前提下,循环操作。
  3. 具体操作是,先从右边开始递减遍历,如发现 <= 基值就跳出循环。
  4. 基于步骤 3 ,在从左边出发开始递增遍历,如发现 > 基值就跳出循环。
  5. 基于步骤 3,4 此时如果左边依然 < 右边,则交换左右的元素值。然后继续步骤 2 的循环。
  6. 这样一来,左右标记最终会重合,这样也就完成了一次分治。
  7. 同样,此时将基值与左或者右标记进行元素交换。
  8. 剩下的仍然是对基值左右两边的数组进行上述的重复过程,直到数组没办法再划分为止。

上面两种划分实现都用到了递归,但其实递归可以转换成栈的操作,因此栈的实现思路是这样的,

联想方法间的调用其实就是入栈的操作,因为在分治的过程中需要知道数组的左右边界,因此可以将左右边界的信息作为栈元素进行操作。所以这个栈的转换我觉得更侧重一个思想,我一开始想的栈的转换是如何利用栈来实现分治操作,一直想不通,后来又看了书才明白是这么转换。

代码

代码实现上分别做了单边循环,双边循环以及栈的转换。

github 地址:Sorting 类下面的 quickSort 方法

举报

相关推荐

0 条评论