【啊哈算法】三、快速排序(二)

本文介绍了如何在仅支持单向遍历的数据结构中实现快速排序,通过单向扫描的思想,利用快慢指针来划分数据,形成三个部分:小于基准、未划分和大于基准的元素。详细阐述了单向扫描的排序过程,并提出了一种递归实现方法,为后续在单链表中应用快速排序奠定了基础。
摘要由CSDN通过智能技术生成

我们在前面的快速排序(一)中已经阐述了快速排序的基本思想,实现以及优化。前面的排序思想适用于所有数据,前提是存储数据的数据结构支持双向遍历,否则不能进行快排,那么我们应该如何给单向数据结构进行快排呢?今天我们就学习单向快排,可以给单向链表等只支持单向遍历的数据结构进行快速排序。

一、单向扫描的快速排序思想

我们先来分析一下上一篇双向扫描的特点,以此来推导单向扫描:为了方便理解,我们将哨兵用 left 和right表示。

双向扫描: left指向开头,right指向结尾,我们以第一遍排序为例,我们将基准选择最左边的一位,就是arr[0],left,right出发:

  • right - -,直到遇到小于基准6的值,定位到了5;
  • left + +,直到遇到大于基准6的值,定位到了7;
  • 交换数值,继续循环,直到相遇。

那么left,right将数据分为了三部分,从【1~left】这部分是小于基准的,【left~right】是还未划分的数据,【right~末尾】这部分是大于基准的:

在这里插入图片描述
那我们现在需要做的就是如何通过单向扫描也把数据划分为3部分,那么就可以双向扫描功能一样,实现一次划分了,从初始位置一次定义两个指针,我们肯定先想到的是通过快慢指针来做,那么我们还是定义left,right,我们利用快慢指针的思想来做,left定位比基准大的值,right继续走,直到right定位小于基准的值,找到后交换,那我们写出单向扫描思想:

单向扫描: 始终以最左边的值作为基准,那我们还是以第一轮排序来详细讲解,基准就是arr[0]的值,right,left指向arr[1]:

  • arr[right]<基准,left++,right++,直到left指向7,大于基准;
  • 那么left定位7的位置,right向后走right++,找小于基准的值,定位到3;
  • 交换数值,left++,right++,循环继续,直到right出右边界。
    在这里插入图片描述

我们可以看到只要小于基准,那么left,right一直走,大于基准,则left不动,right去找小于基准的。那么right和left同样将数据分为了3部分,【1~left】都是小于基准的,【left~right】都是大于基准的,【right~结尾】是未划分的。

我们可以看到单向和双向一轮的结果是一样的,所以我们只用改变划分函数实现即可,下来还是二分递归继续上述过程或者利用栈,那么我们单向扫描快速排序的思想就是:

  • right,left一起走,判断right是否走到了结尾,没有就进入循环;
  • 判断right指向的值是否小于基准,小于则交换arr[left]和arr[right],left++,right++;
  • 如果right指向的值大于基准,则left不动,定位这个值,right继续往后走,直到找到小于基准的值,和left定位的值进行交换。
  • 跳出循环后,将基准和left-1的值交换,将基准归位,一轮结束;
  • 继续递归分为左右继续上述过程,直至元素全部归位。

我们画出一轮划分的详细过程:

在这里插入图片描述

二、实现单向快速排序

那我们就按照思路,写出单向快速排序,代码思路很明确,利用递归分为左右。我用最左边作为基准,当然也可以用我们上次讲过的三位取中,随机数得到基准。

# include
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值