快速排序的分治递归算法

快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序,其基本思想是通过一趟扫描将待排序的元素分割成独立的三个序列:第一个序列中所有元素均不大于基准元素、第二个序列是基准元素、第三个序列中所有元素均大于基准元素。由于第二个序列已经处于正确位置,因此需要再按此方法对第一个序列和第三个序列分别进行排序,整个排序过程可以递归进行,最终可使整个序列变成有序序列。

01

问题分析——分与治的方法

(1) 分解:快速排序的分解是基于基准元素的,所以首先要选定一个元素作为基准元素,然后以选定的基准元素为标杆,将其他元素分成两部分,一部分不大于基准元素,另一部分大于基准元素。

(2) 基准元素的选取:从待排序序列中选取的基准元素是决定算法性能的关键。基准元素的选取应该遵循平衡子问题的原则,即使得划分后的两个子序列的长度尽量相同。基准元素的选择方法有很多种,常用的有以下5种。

① 取第一个元素。即以待排序序列的首元素作为基准元素。

② 取最后一个元素。即以待排序序列的尾元素作为基准元素。

③ 取位于中间位置的元素。即以待排序序列的中间位置的元素作为基准元素。

④ “三者取中的规则”。即在待排序序列中,将该序列的第一个元素、最后一个元素和中间位置的元素进行比较,取三者之中值作为基准元素。

⑤ 随机取一个元素作为基准元素。

(3) 治理:递归不大于基准元素的子序列,然后再递归大于基准元素的子序列,这样不大于基准元素的子序列和大于基准元素的子序列都有序了。基准元素位于正确的位置,整个序列就都有序了,完成了排序的目的。边界条件为子序列且为空或只有1个元素。

02

算法设计

将待排序的n个元素放到列表lis中,用left和right记录子问题在lis中的位置及规模,基准元素记为pivot。首先定义一个partition()函数完成分解任务,然后采用递归方法完成子问题的排序。

在划分过程中,选取待排序元素的第一个元素作为基准元素,然后从左向右、从右向左两个方向轮流找出位置不正确的元素,将其交换位置。该过程一直持续到所有元素都比较结束。最后将基准元素放到正确的位置。

划分操作伪码描述如下:

基于划分的结果,快速排序递归左边的子序列lis[left:j-1],递归右边的子序列lis[j+1:right],伪码描述如下: 

算法:quickSort(lis,left,right)
输入:待排序序列、子问题的边界left和right
输出:有序序列lis
if left < right: 
    j ← partition1(lis,left,right)
    quickSort(arr, left, j-1)
    quickSort(arr, j+1, right)

03

实例构造

给定序列23,15,10,50,93,12,2,68,采用快速排序方法将其升序排列。

(1) 初始序列,如图3-31所示,23为基准元素,i=0,j=8。

■ 图3-31划分初始状态

(2) 从左向右扫描元素:先推动i指针,后比较,若i指向的元素小于或等于基准元素,则继续推动指针、再比较,直到i指向的元素比基准元素大为止,此时i指向的元素位置不正确,应该在右子序列中,所以应该调走,如图3-32所示。

■ 图3-32i指针停止状态

(3) 从右向左扫描元素:先推动j指针,后比较,若j指向的元素大于基准元素,则继续推动指针、比较,直到j指向的元素比基准元素小或相等为止,此时j指向的元素位置不正确,应该在左子序列中,所以应该调走,如图3-33所示。

■ 图3-33j指针停止状态

(4) 交换i指向的元素和j指向的元素,如图3-34所示。

■ 图3-34元素交换后的状态

(5) 由于i<j,所以继续循环,推动i指针,直到i指向的元素大于基准元素;推动j指针,直到j指向的元素小于或等于基准元素,如图3-35所示。

■ 图3-35i指针和j指针第二次扫描停止的状态

(6) 此时i>j,跳出while(True)循环,将基准元素与j指向的元素交换位置,则j便是基准元素的位置,如图3-36所示。

■ 图3-36基准元素放到正确位置的状态

(7) 递归处理左子序列12,15,10,递归处理右子序列93,50,62,68。递归结束的时候,左右子序列均有序了,整个序列也都有序了,如图3-37所示。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

N._

piu~打个赏吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值